r284685 - Refactor and simplify Sema::FindCompositePointerType. No functionality change intended.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 19 18:20:00 PDT 2016
Author: rsmith
Date: Wed Oct 19 20:20:00 2016
New Revision: 284685
URL: http://llvm.org/viewvc/llvm-project?rev=284685&view=rev
Log:
Refactor and simplify Sema::FindCompositePointerType. No functionality change intended.
Modified:
cfe/trunk/lib/Sema/SemaExprCXX.cpp
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=284685&r1=284684&r2=284685&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Oct 19 20:20:00 2016
@@ -5520,7 +5520,7 @@ QualType Sema::CXXCheckConditionalOperan
/// \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(
*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(
// 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(
}
// 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);
-
- 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.
+ 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;
+
+ 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>();
- // Convert E1 to Composite1
- ExprResult E1Result
- = E1ToC1.Perform(*this, Entity1, Kind, E1);
- if (E1Result.isInvalid())
- return QualType();
- E1 = E1Result.getAs<Expr>();
-
- // Convert E2 to Composite1
- ExprResult E2Result
- = E2ToC1.Perform(*this, Entity1, Kind, E2);
- if (E2Result.isInvalid())
- return QualType();
- E2 = E2Result.getAs<Expr>();
-
- return Composite1;
- }
-
- // 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();
+ ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2);
+ if (E2Result.isInvalid())
+ return QualType();
+ E2 = E2Result.getAs<Expr>();
- // Convert E1 to Composite2
- ExprResult E1Result
- = E1ToC2.Perform(*this, Entity2, Kind, E1);
- if (E1Result.isInvalid())
- return QualType();
- E1 = E1Result.getAs<Expr>();
+ return Composite;
+ }
+ };
- // Convert E2 to Composite2
- ExprResult E2Result
- = E2ToC2.Perform(*this, Entity2, Kind, E2);
- if (E2Result.isInvalid())
+ // 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);
+
+ 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();
- E2 = E2Result.getAs<Expr>();
+ }
- return Composite2;
+ // Convert to the chosen type.
+ return (C1.Viable ? C1 : C2).perform();
}
ExprResult Sema::MaybeBindToTemporary(Expr *E) {
More information about the cfe-commits
mailing list