[cfe-commits] r57978 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h lib/Sema/SemaType.cpp test/SemaCXX/overload-call.cpp
Douglas Gregor
doug.gregor at gmail.com
Wed Oct 22 07:17:16 PDT 2008
Author: dgregor
Date: Wed Oct 22 09:17:15 2008
New Revision: 57978
URL: http://llvm.org/viewvc/llvm-project?rev=57978&view=rev
Log:
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).
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaOverload.h
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/SemaCXX/overload-call.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=57978&r1=57977&r2=57978&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Oct 22 09:17:15 2008
@@ -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 {
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=57978&r1=57977&r2=57978&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Oct 22 09:17:15 2008
@@ -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,28 +777,122 @@
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 by qualifications.
// 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;
+ }
+
+ // 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
/// candidate functions, using the given function call arguments.
void
Modified: cfe/trunk/lib/Sema/SemaOverload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=57978&r1=57977&r2=57978&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Wed Oct 22 09:17:15 2008
@@ -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;
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=57978&r1=57977&r2=57978&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Oct 22 09:17:15 2008
@@ -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.
Modified: cfe/trunk/test/SemaCXX/overload-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=57978&r1=57977&r2=57978&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call.cpp Wed Oct 22 09:17:15 2008
@@ -156,11 +156,32 @@
// Test overloading based on qualification ranking (C++ 13.3.2)p3.
int* quals_rank1(int const * p);
float* quals_rank1(int const volatile *p);
+char* quals_rank1(char*);
+double* quals_rank1(const char*);
int* quals_rank2(int const * const * pp);
float* quals_rank2(int * const * pp);
+void quals_rank3(int const * const * const volatile * p); // expected-note{{candidate function}}
+void quals_rank3(int const * const volatile * const * p); // expected-note{{candidate function}}
+
+void quals_rank3(int const *); // expected-note{{candidate function}}
+void quals_rank3(int volatile *); // expected-note{{candidate function}}
+
void test_quals_ranking(int * p, int volatile *pq, int * * pp, int * * * ppp) {
- // int* q1 = quals_rank1(p);
+ int* q1 = quals_rank1(p);
float* q2 = quals_rank1(pq);
+ double* q3 = quals_rank1("string literal");
+ char a[17];
+ const char* ap = a;
+ char* q4 = quals_rank1(a);
+ double* q5 = quals_rank1(ap);
+
+ float* q6 = quals_rank2(pp);
+
+ quals_rank3(ppp); // expected-error {{call to 'quals_rank3' is ambiguous; candidates are:}}
+
+ quals_rank3(p); // expected-error {{call to 'quals_rank3' is ambiguous; candidates are:}}
+ quals_rank3(pq);
}
+
More information about the cfe-commits
mailing list