aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2008-10-23 00:40:37 +0000
committerDouglas Gregor <dgregor@apple.com>2008-10-23 00:40:37 +0000
commitbc0805a6ca84e3c38a08c9f47441e138945244d4 (patch)
treedfcfe1a8fd1085e1e3b95f46cc5a0e1b019a9366 /lib/Sema/SemaOverload.cpp
parent9b3dc9166e6d87af310e1a931303ad75993c7a88 (diff)
Add support for conversions from a pointer-to-derived to a
pointer-to-base. Also, add overload ranking for pointer conversions (for both pointer-to-void and derived-to-base pointer conversions). Note that we do not yet diagnose derived-to-base pointer conversion errors that stem from ambiguous or inacessible base classes. These aren't handled during overload resolution; rather, when the conversion is actually used we go ahead and diagnose the error. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58017 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r--lib/Sema/SemaOverload.cpp145
1 files changed, 138 insertions, 7 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 19bc13a146..c967b04335 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -121,6 +121,30 @@ bool StandardConversionSequence::isPointerConversionToBool() const
return false;
}
+/// isPointerConversionToVoidPointer - Determines whether this
+/// conversion is a conversion of a pointer to a void pointer. This is
+/// used as part of the ranking of standard conversion sequences (C++
+/// 13.3.3.2p4).
+bool
+StandardConversionSequence::
+isPointerConversionToVoidPointer(ASTContext& Context) const
+{
+ QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
+ QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
+
+ // Note that FromType has not necessarily been transformed by the
+ // array-to-pointer implicit conversion, so check for its presence
+ // and redo the conversion to get a pointer.
+ if (First == ICK_Array_To_Pointer)
+ FromType = Context.getArrayDecayedType(FromType);
+
+ if (Second == ICK_Pointer_Conversion)
+ if (const PointerType* ToPtrType = ToType->getAsPointerType())
+ return ToPtrType->getPointeeType()->isVoidType();
+
+ return false;
+}
+
/// DebugPrint - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
void StandardConversionSequence::DebugPrint() const {
@@ -635,9 +659,45 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
return true;
}
- // FIXME: An rvalue of type "pointer to cv D," where D is a class
- // type, can be converted to an rvalue of type "pointer to cv B,"
- // where B is a base class (clause 10) of D (C++ 4.10p3).
+ // C++ [conv.ptr]p3:
+ //
+ // An rvalue of type "pointer to cv D," where D is a class type,
+ // can be converted to an rvalue of type "pointer to cv B," where
+ // B is a base class (clause 10) of D. If B is an inaccessible
+ // (clause 11) or ambiguous (10.2) base class of D, a program that
+ // necessitates this conversion is ill-formed. The result of the
+ // conversion is a pointer to the base class sub-object of the
+ // derived class object. The null pointer value is converted to
+ // the null pointer value of the destination type.
+ //
+ // Note that we do not check for ambiguity or inaccessibility here.
+ if (const PointerType *FromPtrType = FromType->getAsPointerType())
+ if (const PointerType *ToPtrType = ToType->getAsPointerType()) {
+ if (FromPtrType->getPointeeType()->isRecordType() &&
+ ToPtrType->getPointeeType()->isRecordType() &&
+ IsDerivedFrom(FromPtrType->getPointeeType(),
+ ToPtrType->getPointeeType())) {
+ // The conversion is okay. Now, we need to produce the type
+ // that results from this conversion, which will have the same
+ // qualifiers as the incoming type.
+ QualType CanonFromPointee
+ = Context.getCanonicalType(FromPtrType->getPointeeType());
+ QualType ToPointee = ToPtrType->getPointeeType();
+ QualType CanonToPointee = Context.getCanonicalType(ToPointee);
+ unsigned Quals = CanonFromPointee.getCVRQualifiers();
+
+ if (CanonToPointee.getCVRQualifiers() == Quals) {
+ // ToType is exactly the type we want. Use it.
+ ConvertedType = ToType;
+ } else {
+ // Build a new type with the right qualifiers.
+ ConvertedType
+ = Context.getPointerType(CanonToPointee.getQualifiedType(Quals));
+ }
+ return true;
+ }
+ }
+
return false;
}
@@ -790,14 +850,30 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
- // FIXME: The other bullets in (C++ 13.3.3.2p4) require support
- // for derived classes.
+ // C++ [over.ics.rank]p4b2:
+ //
+ // If class B is derived directly or indirectly from class A,
+ // conversion of B* to A* is better than conversion of B* to void*,
+ // and (FIXME) conversion of A* to void* is better than conversion of B*
+ // to void*.
+ bool SCS1ConvertsToVoid
+ = SCS1.isPointerConversionToVoidPointer(Context);
+ bool SCS2ConvertsToVoid
+ = SCS2.isPointerConversionToVoidPointer(Context);
+ if (SCS1ConvertsToVoid != SCS2ConvertsToVoid)
+ return SCS2ConvertsToVoid ? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
+
+ if (!SCS1ConvertsToVoid && !SCS2ConvertsToVoid)
+ if (ImplicitConversionSequence::CompareKind DerivedCK
+ = CompareDerivedToBaseConversions(SCS1, SCS2))
+ return DerivedCK;
// Compare based on qualification conversions (C++ 13.3.3.2p3,
// bullet 3).
- if (ImplicitConversionSequence::CompareKind CK
+ if (ImplicitConversionSequence::CompareKind QualCK
= CompareQualificationConversions(SCS1, SCS2))
- return CK;
+ return QualCK;
// FIXME: Handle comparison of reference bindings.
@@ -894,6 +970,61 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
return Result;
}
+/// CompareDerivedToBaseConversions - Compares two standard conversion
+/// sequences to determine whether they can be ranked based on their
+/// various kinds of derived-to-base conversions (C++ [over.ics.rank]p4b3).
+ImplicitConversionSequence::CompareKind
+Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2) {
+ QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr);
+ QualType ToType1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
+ QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr);
+ QualType ToType2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+
+ // Adjust the types we're converting from via the array-to-pointer
+ // conversion, if we need to.
+ if (SCS1.First == ICK_Array_To_Pointer)
+ FromType1 = Context.getArrayDecayedType(FromType1);
+ if (SCS2.First == ICK_Array_To_Pointer)
+ FromType2 = Context.getArrayDecayedType(FromType2);
+
+ // Canonicalize all of the types.
+ FromType1 = Context.getCanonicalType(FromType1);
+ ToType1 = Context.getCanonicalType(ToType1);
+ FromType2 = Context.getCanonicalType(FromType2);
+ ToType2 = Context.getCanonicalType(ToType2);
+
+ // C++ [over.ics.rank]p4b4:
+ //
+ // If class B is derived directly or indirectly from class A and
+ // class C is derived directly or indirectly from B,
+ //
+ // FIXME: Verify that in this section we're talking about the
+ // unqualified forms of C, B, and A.
+ if (SCS1.Second == ICK_Pointer_Conversion &&
+ SCS2.Second == ICK_Pointer_Conversion) {
+ // -- conversion of C* to B* is better than conversion of C* to A*,
+ QualType FromPointee1
+ = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee1
+ = ToType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee2
+ = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee2
+ = ToType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
+ if (IsDerivedFrom(ToPointee1, ToPointee2))
+ return ImplicitConversionSequence::Better;
+ else if (IsDerivedFrom(ToPointee2, ToPointee1))
+ return ImplicitConversionSequence::Worse;
+ }
+ }
+
+ // FIXME: many more sub-bullets of C++ [over.ics.rank]p4b4 to
+ // implement.
+ return ImplicitConversionSequence::Indistinguishable;
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments.
void