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).
 

llvm-svn: 57978
This commit is contained in:
Douglas Gregor 2008-10-22 14:17:15 +00:00
parent 2fbc35443d
commit e1eb9d8cc4
5 changed files with 171 additions and 42 deletions

View File

@ -262,7 +262,8 @@ public:
QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
private:
//===--------------------------------------------------------------------===//
@ -380,6 +381,10 @@ private:
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 {

View File

@ -659,46 +659,32 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
// 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 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
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

View File

@ -170,9 +170,9 @@ namespace clang {
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.
enum CompareKind {
Better,
Indistinguishable,
Worse
Better = -1,
Indistinguishable = 0,
Worse = 1
};
void DebugPrint() const;

View File

@ -535,6 +535,29 @@ QualType Sema::ObjCGetTypeForMethodDefinition(DeclTy *D) {
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.

View File

@ -156,11 +156,32 @@ void test_quals(int * p, int * * pp, int * * * ppp) {
// 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);
}