Refactor and simplify Sema::FindCompositePointerType. No functionality change intended.

llvm-svn: 284685
This commit is contained in:
Richard Smith 2016-10-20 01:20:00 +00:00
parent 6609443f2f
commit 6ffdb1f3ed
1 changed files with 123 additions and 126 deletions

View File

@ -5520,7 +5520,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
/// \brief Find a merged pointer type and convert the two expressions to it.
///
/// This finds the composite pointer type (or member pointer type) for @p E1
/// and @p E2 according to C++11 5.9p2. It converts both expressions to this
/// and @p E2 according to C++1z 5p14. It converts both expressions to this
/// type and returns it.
/// It does not emit diagnostics.
///
@ -5538,69 +5538,87 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
*NonStandardCompositeType = false;
assert(getLangOpts().CPlusPlus && "This function assumes C++");
// C++1z [expr]p14:
// The composite pointer type of two operands p1 and p2 having types T1
// and T2
QualType T1 = E1->getType(), T2 = E2->getType();
// C++11 5.9p2
// Pointer conversions and qualification conversions are performed on
// pointer operands to bring them to their composite pointer type. If
// one operand is a null pointer constant, the composite pointer type is
// std::nullptr_t if the other operand is also a null pointer constant or,
// if the other operand is a pointer, the type of the other operand.
if (!T1->isAnyPointerType() && !T1->isMemberPointerType() &&
!T2->isAnyPointerType() && !T2->isMemberPointerType()) {
if (T1->isNullPtrType() &&
E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get();
return T1;
}
if (T2->isNullPtrType() &&
E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get();
return T2;
}
// where at least one is a pointer or pointer to member type or
// std::nullptr_t is:
bool T1IsPointerLike = T1->isAnyPointerType() || T1->isMemberPointerType() ||
T1->isNullPtrType();
bool T2IsPointerLike = T2->isAnyPointerType() || T2->isMemberPointerType() ||
T2->isNullPtrType();
if (!T1IsPointerLike && !T2IsPointerLike)
return QualType();
}
if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
if (T2->isMemberPointerType())
E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).get();
else
E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get();
return T2;
}
if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
if (T1->isMemberPointerType())
E2 = ImpCastExprToType(E2, T1, CK_NullToMemberPointer).get();
else
E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get();
// - if both p1 and p2 are null pointer constants, std::nullptr_t;
// This can't actually happen, following the standard, but we also use this
// to implement the end of [expr.conv], which hits this case.
//
// - if either p1 or p2 is a null pointer constant, T2 or T1, respectively;
if (T1IsPointerLike &&
E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer).get();
return T1;
}
if (T2IsPointerLike &&
E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer).get();
return T2;
}
// Now both have to be pointers or member pointers.
if ((!T1->isPointerType() && !T1->isMemberPointerType()) ||
(!T2->isPointerType() && !T2->isMemberPointerType()))
if (!T1IsPointerLike || !T2IsPointerLike)
return QualType();
assert(!T1->isNullPtrType() && !T2->isNullPtrType() &&
"nullptr_t should be a null pointer constant");
// Otherwise, of one of the operands has type "pointer to cv1 void," then
// the other has type "pointer to cv2 T" and the composite pointer type is
// "pointer to cv12 void," where cv12 is the union of cv1 and cv2.
// Otherwise, the composite pointer type is a pointer type similar to the
// type of one of the operands, with a cv-qualification signature that is
// the union of the cv-qualification signatures of the operand types.
// In practice, the first part here is redundant; it's subsumed by the second.
// What we do here is, we build the two possible composite types, and try the
// conversions in both directions. If only one works, or if the two composite
// types are the same, we have succeeded.
// - if T1 or T2 is "pointer to cv1 void" and the other type is
// "pointer to cv2 T", "pointer to cv12 void", where cv12 is
// the union of cv1 and cv2;
// - if T1 or T2 is "pointer to noexcept function" and the other type is
// "pointer to function", where the function types are otherwise the same,
// "pointer to function";
// FIXME: This rule is defective: it should also permit removing noexcept
// from a pointer to member function. As a Clang extension, we also
// permit removing 'noreturn', so we generalize this rule to;
// - [Clang] If T1 and T2 are both of type "pointer to function" or
// "pointer to member function" and the pointee types can be unified
// by a function pointer conversion, that conversion is applied
// before checking the following rules.
// - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1
// is reference-related to C2 or C2 is reference-related to C1 (8.6.3),
// the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1,
// respectively;
// - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer
// to member of C2 of type cv2 U2" where C1 is reference-related to C2 or
// C2 is reference-related to C1 (8.6.3), the cv-combined type of T2 and
// T1 or the cv-combined type of T1 and T2, respectively;
// - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and
// T2;
//
// If looked at in the right way, these bullets all do the same thing.
// What we do here is, we build the two possible cv-combined types, and try
// the conversions in both directions. If only one works, or if the two
// composite types are the same, we have succeeded.
// FIXME: extended qualifiers?
typedef SmallVector<unsigned, 4> QualifierVector;
QualifierVector QualifierUnion;
typedef SmallVector<std::pair<const Type *, const Type *>, 4>
ContainingClassVector;
ContainingClassVector MemberOfClass;
QualType Composite1 = Context.getCanonicalType(T1),
Composite2 = Context.getCanonicalType(T2);
//
// Note that this will fail to find a composite pointer type for "pointer
// to void" and "pointer to function". We can't actually perform the final
// conversion in this case, even though a composite pointer type formally
// exists.
SmallVector<unsigned, 4> QualifierUnion;
SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
QualType Composite1 = Context.getCanonicalType(T1);
QualType Composite2 = Context.getCanonicalType(T2);
unsigned NeedConstBefore = 0;
do {
while (true) {
const PointerType *Ptr1, *Ptr2;
if ((Ptr1 = Composite1->getAs<PointerType>()) &&
(Ptr2 = Composite2->getAs<PointerType>())) {
@ -5642,7 +5660,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// Cannot unwrap any more types.
break;
} while (true);
}
if (NeedConstBefore && NonStandardCompositeType) {
// Extension: Add 'const' to qualifiers that come before the first qualifier
@ -5657,94 +5675,73 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
}
// Rewrap the composites as pointers or member pointers with the union CVRs.
ContainingClassVector::reverse_iterator MOC
= MemberOfClass.rbegin();
for (QualifierVector::reverse_iterator
I = QualifierUnion.rbegin(),
E = QualifierUnion.rend();
I != E; (void)++I, ++MOC) {
Qualifiers Quals = Qualifiers::fromCVRMask(*I);
if (MOC->first && MOC->second) {
auto MOC = MemberOfClass.rbegin();
for (unsigned CVR : llvm::reverse(QualifierUnion)) {
Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
auto Classes = *MOC++;
if (Classes.first && Classes.second) {
// Rebuild member pointer type
Composite1 = Context.getMemberPointerType(
Context.getQualifiedType(Composite1, Quals),
MOC->first);
Context.getQualifiedType(Composite1, Quals), Classes.first);
Composite2 = Context.getMemberPointerType(
Context.getQualifiedType(Composite2, Quals),
MOC->second);
Context.getQualifiedType(Composite2, Quals), Classes.second);
} else {
// Rebuild pointer type
Composite1
= Context.getPointerType(Context.getQualifiedType(Composite1, Quals));
Composite2
= Context.getPointerType(Context.getQualifiedType(Composite2, Quals));
Composite1 =
Context.getPointerType(Context.getQualifiedType(Composite1, Quals));
Composite2 =
Context.getPointerType(Context.getQualifiedType(Composite2, Quals));
}
}
// Try to convert to the first composite pointer type.
InitializedEntity Entity1
= InitializedEntity::InitializeTemporary(Composite1);
InitializationKind Kind
= InitializationKind::CreateCopy(Loc, SourceLocation());
InitializationSequence E1ToC1(*this, Entity1, Kind, E1);
InitializationSequence E2ToC1(*this, Entity1, Kind, E2);
struct Conversion {
Sema &S;
SourceLocation Loc;
Expr *&E1, *&E2;
QualType Composite;
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(Composite);
InitializationKind Kind =
InitializationKind::CreateCopy(Loc, SourceLocation());
InitializationSequence E1ToC, E2ToC;
bool Viable = E1ToC && E2ToC;
if (E1ToC1 && E2ToC1) {
// Conversion to Composite1 is viable.
if (!Context.hasSameType(Composite1, Composite2)) {
// Composite2 is a different type from Composite1. Check whether
// Composite2 is also viable.
InitializedEntity Entity2
= InitializedEntity::InitializeTemporary(Composite2);
InitializationSequence E1ToC2(*this, Entity2, Kind, E1);
InitializationSequence E2ToC2(*this, Entity2, Kind, E2);
if (E1ToC2 && E2ToC2) {
// Both Composite1 and Composite2 are viable and are different;
// this is an ambiguity.
Conversion(Sema &S, SourceLocation Loc, Expr *&E1, Expr *&E2,
QualType Composite)
: S(S), Loc(Loc), E1(E1), E2(E2), Composite(Composite),
E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2) {
}
QualType perform() {
ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1);
if (E1Result.isInvalid())
return QualType();
}
E1 = E1Result.getAs<Expr>();
ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2);
if (E2Result.isInvalid())
return QualType();
E2 = E2Result.getAs<Expr>();
return Composite;
}
};
// Convert E1 to Composite1
ExprResult E1Result
= E1ToC1.Perform(*this, Entity1, Kind, E1);
if (E1Result.isInvalid())
return QualType();
E1 = E1Result.getAs<Expr>();
// Try to convert to each composite pointer type.
Conversion C1(*this, Loc, E1, E2, Composite1);
if (C1.Viable && Context.hasSameType(Composite1, Composite2))
return C1.perform();
Conversion C2(*this, Loc, E1, E2, Composite2);
// Convert E2 to Composite1
ExprResult E2Result
= E2ToC1.Perform(*this, Entity1, Kind, E2);
if (E2Result.isInvalid())
return QualType();
E2 = E2Result.getAs<Expr>();
return Composite1;
if (C1.Viable == C2.Viable) {
// Either Composite1 and Composite2 are viable and are different, or
// neither is viable.
// FIXME: How both be viable and different?
return QualType();
}
// Check whether Composite2 is viable.
InitializedEntity Entity2
= InitializedEntity::InitializeTemporary(Composite2);
InitializationSequence E1ToC2(*this, Entity2, Kind, E1);
InitializationSequence E2ToC2(*this, Entity2, Kind, E2);
if (!E1ToC2 || !E2ToC2)
return QualType();
// Convert E1 to Composite2
ExprResult E1Result
= E1ToC2.Perform(*this, Entity2, Kind, E1);
if (E1Result.isInvalid())
return QualType();
E1 = E1Result.getAs<Expr>();
// Convert E2 to Composite2
ExprResult E2Result
= E2ToC2.Perform(*this, Entity2, Kind, E2);
if (E2Result.isInvalid())
return QualType();
E2 = E2Result.getAs<Expr>();
return Composite2;
// Convert to the chosen type.
return (C1.Viable ? C1 : C2).perform();
}
ExprResult Sema::MaybeBindToTemporary(Expr *E) {