Implement ranking of standard conversion sequences by their qualification
conversions (e.g., comparing int* -> const int* against
int* -> const volatile int*); see C++ 13.3.3.2p3 bullet 3.
Add Sema::UnwrapSimilarPointerTypes to simplify the control flow of
IsQualificationConversion and CompareQualificationConversion (and fix
the handling of the int* -> volatile int* conversion in the former).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57978 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 2508d1a..b176bc9 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -262,7 +262,8 @@
QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
-
+ bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
+
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
private:
//===--------------------------------------------------------------------===//
@@ -380,6 +381,10 @@
CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
+ ImplicitConversionSequence::CompareKind
+ CompareQualificationConversions(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2);
+
/// OverloadingResult - Capture the result of performing overload
/// resolution.
enum OverloadingResult {
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 6d01709..8e44025 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -659,46 +659,32 @@
// A conversion can add cv-qualifiers at levels other than the first
// in multi-level pointers, subject to the following rules: [...]
bool PreviousToQualsIncludeConst = true;
- bool UnwrappedPointer;
bool UnwrappedAnyPointer = false;
- do {
+ while (UnwrapSimilarPointerTypes(FromType, ToType)) {
// Within each iteration of the loop, we check the qualifiers to
// determine if this still looks like a qualification
// conversion. Then, if all is well, we unwrap one more level of
// pointers (FIXME: or pointers-to-members) and do it all again
// until there are no more pointers or pointers-to-members left to
// unwrap.
- UnwrappedPointer = false;
-
- // -- the pointer types are similar.
- const PointerType *FromPtrType = FromType->getAsPointerType(),
- *ToPtrType = ToType->getAsPointerType();
- if (FromPtrType && ToPtrType) {
- // The pointer types appear similar. Look at their pointee types.
- FromType = FromPtrType->getPointeeType();
- ToType = ToPtrType->getPointeeType();
- UnwrappedPointer = true;
- UnwrappedAnyPointer = true;
- }
-
- // FIXME: Cope with pointer-to-member types.
+ UnwrappedAnyPointer = true;
// -- for every j > 0, if const is in cv 1,j then const is in cv
// 2,j, and similarly for volatile.
if (!ToType.isAtLeastAsQualifiedAs(FromType))
return false;
-
+
// -- if the cv 1,j and cv 2,j are different, then const is in
// every cv for 0 < k < j.
if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
- && !PreviousToQualsIncludeConst)
+ && !PreviousToQualsIncludeConst)
return false;
-
+
// Keep track of whether all prior cv-qualifiers in the "to" type
// include const.
PreviousToQualsIncludeConst
= PreviousToQualsIncludeConst && ToType.isConstQualified();
- } while (UnwrappedPointer);
+ }
// We are left with FromType and ToType being the pointee types
// after unwrapping the original FromType and ToType the same number
@@ -791,26 +777,120 @@
return ImplicitConversionSequence::Better;
else if (Rank2 < Rank1)
return ImplicitConversionSequence::Worse;
- else {
- // (C++ 13.3.3.2p4): Two conversion sequences with the same rank
- // are indistinguishable unless one of the following rules
- // applies:
-
- // A conversion that is not a conversion of a pointer, or
- // pointer to member, to bool is better than another conversion
- // that is such a conversion.
- if (SCS1.isPointerConversionToBool() != SCS2.isPointerConversionToBool())
- return SCS2.isPointerConversionToBool()
- ? ImplicitConversionSequence::Better
- : ImplicitConversionSequence::Worse;
- // FIXME: The other bullets in (C++ 13.3.3.2p4) require support
- // for derived classes.
+ // (C++ 13.3.3.2p4): Two conversion sequences with the same rank
+ // are indistinguishable unless one of the following rules
+ // applies:
+
+ // A conversion that is not a conversion of a pointer, or
+ // pointer to member, to bool is better than another conversion
+ // that is such a conversion.
+ if (SCS1.isPointerConversionToBool() != SCS2.isPointerConversionToBool())
+ return SCS2.isPointerConversionToBool()
+ ? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
+
+ // FIXME: The other bullets in (C++ 13.3.3.2p4) require support
+ // for derived classes.
+
+ // Compare based on qualification conversions (C++ 13.3.3.2p3,
+ // bullet 3).
+ if (ImplicitConversionSequence::CompareKind CK
+ = CompareQualificationConversions(SCS1, SCS2))
+ return CK;
+
+ // FIXME: Handle comparison of reference bindings.
+
+ return ImplicitConversionSequence::Indistinguishable;
+}
+
+/// CompareQualificationConversions - Compares two standard conversion
+/// sequences to determine whether they can be ranked based on their
+/// qualification conversions (C++ 13.3.3.2p3 bullet 3).
+ImplicitConversionSequence::CompareKind
+Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2)
+{
+ // -- S1 and S2 differ only in their qualification conversion and
+ // yield similar types T1 and T2 (C++ 4.4), respectively, and the
+ // cv-qualification signature of type T1 is a proper subset of
+ // the cv-qualification signature of type T2, and S1 is not the
+ // deprecated string literal array-to-pointer conversion (4.2).
+ if (SCS1.First != SCS2.First || SCS1.Second != SCS2.Second ||
+ SCS1.Third != SCS2.Third || SCS1.Third != ICK_Qualification)
+ return ImplicitConversionSequence::Indistinguishable;
+
+ // FIXME: the example in the standard doesn't use a qualification
+ // conversion (!)
+ QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
+ QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ T1 = Context.getCanonicalType(T1);
+ T2 = Context.getCanonicalType(T2);
+
+ // If the types are the same, we won't learn anything by unwrapped
+ // them.
+ if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
+ return ImplicitConversionSequence::Indistinguishable;
+
+ ImplicitConversionSequence::CompareKind Result
+ = ImplicitConversionSequence::Indistinguishable;
+ while (UnwrapSimilarPointerTypes(T1, T2)) {
+ // Within each iteration of the loop, we check the qualifiers to
+ // determine if this still looks like a qualification
+ // conversion. Then, if all is well, we unwrap one more level of
+ // pointers (FIXME: or pointers-to-members) and do it all again
+ // until there are no more pointers or pointers-to-members left
+ // to unwrap. This essentially mimics what
+ // IsQualificationConversion does, but here we're checking for a
+ // strict subset of qualifiers.
+ if (T1.getCVRQualifiers() == T2.getCVRQualifiers())
+ // The qualifiers are the same, so this doesn't tell us anything
+ // about how the sequences rank.
+ ;
+ else if (T2.isMoreQualifiedThan(T1)) {
+ // T1 has fewer qualifiers, so it could be the better sequence.
+ if (Result == ImplicitConversionSequence::Worse)
+ // Neither has qualifiers that are a subset of the other's
+ // qualifiers.
+ return ImplicitConversionSequence::Indistinguishable;
+
+ Result = ImplicitConversionSequence::Better;
+ } else if (T1.isMoreQualifiedThan(T2)) {
+ // T2 has fewer qualifiers, so it could be the better sequence.
+ if (Result == ImplicitConversionSequence::Better)
+ // Neither has qualifiers that are a subset of the other's
+ // qualifiers.
+ return ImplicitConversionSequence::Indistinguishable;
+
+ Result = ImplicitConversionSequence::Worse;
+ } else {
+ // Qualifiers are disjoint.
+ return ImplicitConversionSequence::Indistinguishable;
+ }
+
+ // If the types after this point are equivalent, we're done.
+ if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
+ break;
}
- // FIXME: Handle comparison by qualifications.
- // FIXME: Handle comparison of reference bindings.
- return ImplicitConversionSequence::Indistinguishable;
+ // Check that the winning standard conversion sequence isn't using
+ // the deprecated string literal array to pointer conversion.
+ switch (Result) {
+ case ImplicitConversionSequence::Better:
+ if (SCS1.Deprecated)
+ Result = ImplicitConversionSequence::Indistinguishable;
+ break;
+
+ case ImplicitConversionSequence::Indistinguishable:
+ break;
+
+ case ImplicitConversionSequence::Worse:
+ if (SCS2.Deprecated)
+ Result = ImplicitConversionSequence::Indistinguishable;
+ break;
+ }
+
+ return Result;
}
/// AddOverloadCandidate - Adds the given function to the set of
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 8d7ccd2..f9e03ae 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -170,9 +170,9 @@
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.
enum CompareKind {
- Better,
- Indistinguishable,
- Worse
+ Better = -1,
+ Indistinguishable = 0,
+ Worse = 1
};
void DebugPrint() const;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index f1edabf..82e16cf 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -535,6 +535,29 @@
return T;
}
+/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types (FIXME:
+/// or pointer-to-member types) that may be similar (C++ 4.4),
+/// replaces T1 and T2 with the type that they point to and return
+/// true. If T1 and T2 aren't pointer types or pointer-to-member
+/// types, or if they are not similar at this level, returns false and
+/// leaves T1 and T2 unchanged. Top-level qualifiers on T1 and T2 are
+/// ignord. This function will typically be called in a loop that
+/// successively "unwraps" pointer and pointer-to-member types to
+/// compare them at each level.
+bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2)
+{
+ const PointerType *T1PtrType = T1->getAsPointerType(),
+ *T2PtrType = T2->getAsPointerType();
+ if (T1PtrType && T2PtrType) {
+ T1 = T1PtrType->getPointeeType();
+ T2 = T2PtrType->getPointeeType();
+ return true;
+ }
+
+ // FIXME: pointer-to-member types
+ return false;
+}
+
Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// C99 6.7.6: Type names have no identifier. This is already validated by
// the parser.