aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-06-09 03:53:18 +0000
committerDouglas Gregor <dgregor@apple.com>2010-06-09 03:53:18 +0000
commit5a57efd7bf88a4a13018e0471ded8063a4abe8af (patch)
tree413e2332fc0ba640561634578a3fea72271f6027
parente140af3e27016f902146023fba7680b43043ec07 (diff)
Tweak our handling of the notion of a standard conversion sequence
being a subsequence of another standard conversion sequence. Instead of requiring exact type equality for the second conversion step, require type *similarity*, which is type equality with cv-qualifiers removed at all levels. This appears to match the behavior of EDG and VC++ (albeit not GCC), and feels more intuitive. Big thanks to John for the line of reasoning that supports this change: since cv-qualifiers are orthogonal to the second conversion step, we should ignore them in the type comparison. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105678 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h2
-rw-r--r--lib/AST/ASTContext.cpp42
-rw-r--r--lib/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaCXXCast.cpp2
-rw-r--r--lib/Sema/SemaOverload.cpp16
-rw-r--r--lib/Sema/SemaType.cpp39
-rw-r--r--test/SemaCXX/overload-call.cpp17
7 files changed, 75 insertions, 45 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index b2da3d0b73..9746b0dfd3 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -1015,6 +1015,8 @@ public:
return UnqualT1 == UnqualT2;
}
+ bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
+
/// \brief Retrieves the "canonical" declaration of
/// \brief Retrieves the "canonical" nested name specifier for a
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 75af89ee96..2e72449575 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2339,6 +2339,48 @@ QualType ASTContext::getUnqualifiedArrayType(QualType T,
SourceRange());
}
+/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer 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 ignored. 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 ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) {
+ const PointerType *T1PtrType = T1->getAs<PointerType>(),
+ *T2PtrType = T2->getAs<PointerType>();
+ if (T1PtrType && T2PtrType) {
+ T1 = T1PtrType->getPointeeType();
+ T2 = T2PtrType->getPointeeType();
+ return true;
+ }
+
+ const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
+ *T2MPType = T2->getAs<MemberPointerType>();
+ if (T1MPType && T2MPType &&
+ hasSameUnqualifiedType(QualType(T1MPType->getClass(), 0),
+ QualType(T2MPType->getClass(), 0))) {
+ T1 = T1MPType->getPointeeType();
+ T2 = T2MPType->getPointeeType();
+ return true;
+ }
+
+ if (getLangOptions().ObjC1) {
+ const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(),
+ *T2OPType = T2->getAs<ObjCObjectPointerType>();
+ if (T1OPType && T2OPType) {
+ T1 = T1OPType->getPointeeType();
+ T2 = T2OPType->getPointeeType();
+ return true;
+ }
+ }
+
+ // FIXME: Block pointers, too?
+
+ return false;
+}
+
DeclarationName ASTContext::getNameForTemplate(TemplateName Name) {
if (TemplateDecl *TD = Name.getAsTemplateDecl())
return TD->getDeclName();
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 25f4e9d6c1..48b8d05d91 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -769,8 +769,6 @@ public:
const FunctionProtoType *Target, SourceLocation TargetLoc,
const FunctionProtoType *Source, SourceLocation SourceLoc);
- bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
-
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
bool RequireCompleteType(SourceLocation Loc, QualType T,
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 5485bb3e17..16f0af14d2 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -1019,7 +1019,7 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
// in multi-level pointers may change, but the level count must be the same,
// as must be the final pointee type.
while (SrcType != DestType &&
- Self.UnwrapSimilarPointerTypes(SrcType, DestType)) {
+ Self.Context.UnwrapSimilarPointerTypes(SrcType, DestType)) {
Qualifiers Quals;
SrcType = Self.Context.getUnqualifiedArrayType(SrcType, Quals);
DestType = Self.Context.getUnqualifiedArrayType(DestType, Quals);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index d746ec3f6d..721c68f6c1 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1785,7 +1785,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
// in multi-level pointers, subject to the following rules: [...]
bool PreviousToQualsIncludeConst = true;
bool UnwrappedAnyPointer = false;
- while (UnwrapSimilarPointerTypes(FromType, ToType)) {
+ while (Context.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
@@ -2073,6 +2073,16 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
return ImplicitConversionSequence::Indistinguishable;
}
+static bool hasSimilarType(ASTContext &Context, QualType T1, QualType T2) {
+ while (Context.UnwrapSimilarPointerTypes(T1, T2)) {
+ Qualifiers Quals;
+ T1 = Context.getUnqualifiedArrayType(T1, Quals);
+ T2 = Context.getUnqualifiedArrayType(T2, Quals);
+ }
+
+ return Context.hasSameUnqualifiedType(T1, T2);
+}
+
// Per 13.3.3.2p3, compare the given standard conversion sequences to
// determine if one is a proper subset of the other.
static ImplicitConversionSequence::CompareKind
@@ -2098,7 +2108,7 @@ compareStandardConversionSubsets(ASTContext &Context,
Result = ImplicitConversionSequence::Worse;
else
return ImplicitConversionSequence::Indistinguishable;
- } else if (!Context.hasSameType(SCS1.getToType(1), SCS2.getToType(1)))
+ } else if (!hasSimilarType(Context, SCS1.getToType(1), SCS2.getToType(1)))
return ImplicitConversionSequence::Indistinguishable;
if (SCS1.Third == SCS2.Third) {
@@ -2305,7 +2315,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
- while (UnwrapSimilarPointerTypes(T1, T2)) {
+ while (Context.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
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 8242f61897..8327fd2686 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1611,45 +1611,6 @@ void LocInfoType::getAsStringInternal(std::string &Str,
" GetTypeFromParser");
}
-/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer 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 ignored. 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->getAs<PointerType>(),
- *T2PtrType = T2->getAs<PointerType>();
- if (T1PtrType && T2PtrType) {
- T1 = T1PtrType->getPointeeType();
- T2 = T2PtrType->getPointeeType();
- return true;
- }
-
- const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
- *T2MPType = T2->getAs<MemberPointerType>();
- if (T1MPType && T2MPType &&
- Context.getCanonicalType(T1MPType->getClass()) ==
- Context.getCanonicalType(T2MPType->getClass())) {
- T1 = T1MPType->getPointeeType();
- T2 = T2MPType->getPointeeType();
- return true;
- }
-
- if (getLangOptions().ObjC1) {
- const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(),
- *T2OPType = T2->getAs<ObjCObjectPointerType>();
- if (T1OPType && T2OPType) {
- T1 = T1OPType->getPointeeType();
- T2 = T2OPType->getPointeeType();
- return true;
- }
- }
- 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.
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 29133c7c7f..9df5bc9f0c 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -460,3 +460,20 @@ namespace PR7224 {
float &fr = foo(d2);
}
}
+
+namespace NontrivialSubsequence {
+ struct X0;
+
+ class A {
+ operator X0 *();
+ public:
+ operator const X0 *();
+ };
+
+ A a;
+ void foo( void const * );
+
+ void g() {
+ foo(a);
+ }
+}