[cfe-commits] r58017 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaInherit.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/overload-call.cpp
Douglas Gregor
doug.gregor at gmail.com
Wed Oct 22 17:40:37 PDT 2008
Author: dgregor
Date: Wed Oct 22 19:40:37 2008
New Revision: 58017
URL: http://llvm.org/viewvc/llvm-project?rev=58017&view=rev
Log:
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.
Added:
cfe/trunk/lib/Sema/SemaInherit.cpp
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaOverload.h
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=58017&r1=58016&r2=58017&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Oct 22 19:40:37 2008
@@ -385,6 +385,10 @@
CompareQualificationConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
+ ImplicitConversionSequence::CompareKind
+ CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2);
+
/// OverloadingResult - Capture the result of performing overload
/// resolution.
enum OverloadingResult {
@@ -752,14 +756,6 @@
//===--------------------------------------------------------------------===//
// C++ Classes
//
- /// ActOnBaseSpecifier - Parsed a base specifier
- virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl,
- SourceRange SpecifierRange,
- bool Virtual, AccessSpecifier Access,
- TypeTy *basetype, SourceLocation BaseLoc);
-
- virtual void ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
- unsigned NumBases);
virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
SourceLocation LBrace);
@@ -775,6 +771,20 @@
virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl);
+ //===--------------------------------------------------------------------===//
+ // C++ Derived Classes
+ //
+
+ /// ActOnBaseSpecifier - Parsed a base specifier
+ virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl,
+ SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ TypeTy *basetype, SourceLocation BaseLoc);
+
+ virtual void ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
+ unsigned NumBases);
+
+ bool IsDerivedFrom(QualType Derived, QualType Base);
// Objective-C declarations.
virtual DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
Added: cfe/trunk/lib/Sema/SemaInherit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInherit.cpp?rev=58017&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/SemaInherit.cpp (added)
+++ cfe/trunk/lib/Sema/SemaInherit.cpp Wed Oct 22 19:40:37 2008
@@ -0,0 +1,54 @@
+//===---- SemaInherit.cpp - C++ Inheritance ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides Sema routines for C++ inheritance semantics,
+// including searching the inheritance hierarchy and (eventually)
+// access checking.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+
+namespace clang {
+
+/// IsDerivedFrom - Determine whether the class type Derived is
+/// derived from the class type Base, ignoring qualifiers on Base and
+/// Derived. This routine does not assess whether an actual conversion
+/// from a Derived* to a Base* is legal, because it does not account
+/// for ambiguous conversions or conversions to private/protected
+/// bases.
+bool Sema::IsDerivedFrom(QualType Derived, QualType Base)
+{
+ Derived = Context.getCanonicalType(Derived).getUnqualifiedType();
+ Base = Context.getCanonicalType(Base).getUnqualifiedType();
+
+ assert(Derived->isRecordType() && "IsDerivedFrom requires a class type");
+ assert(Base->isRecordType() && "IsDerivedFrom requires a class type");
+
+ if (Derived == Base)
+ return false;
+
+ if (const RecordType *DerivedType = Derived->getAsRecordType()) {
+ const CXXRecordDecl *Decl
+ = static_cast<const CXXRecordDecl *>(DerivedType->getDecl());
+ for (unsigned idx = 0; idx < Decl->getNumBases(); ++idx) {
+ const CXXBaseSpecifier *BaseSpec = Decl->getBase(idx);
+ if (Context.getCanonicalType(BaseSpec->getType()) == Base
+ || IsDerivedFrom(BaseSpec->getType(), Base))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // end namespace clang
+
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=58017&r1=58016&r2=58017&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Oct 22 19:40:37 2008
@@ -121,6 +121,30 @@
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 @@
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 @@
? 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 @@
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
Modified: cfe/trunk/lib/Sema/SemaOverload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=58017&r1=58016&r2=58017&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Wed Oct 22 19:40:37 2008
@@ -97,17 +97,17 @@
bool Deprecated : 1;
/// FromType - The type that this conversion is converting
- /// from. This is an opaque pointer for that can be translated
- /// into a QualType.
+ /// from. This is an opaque pointer that can be translated into a
+ /// QualType.
void *FromTypePtr;
/// ToType - The type that this conversion is converting to. This
- /// is an opaque pointer for that can be translated into a
- /// QualType.
+ /// is an opaque pointer that can be translated into a QualType.
void *ToTypePtr;
ImplicitConversionRank getRank() const;
bool isPointerConversionToBool() const;
+ bool isPointerConversionToVoidPointer(ASTContext& Context) const;
void DebugPrint() const;
};
Modified: cfe/trunk/test/SemaCXX/overload-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=58017&r1=58016&r2=58017&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call.cpp Wed Oct 22 19:40:37 2008
@@ -185,3 +185,32 @@
quals_rank3(pq);
}
+// Test overloading based on derived-to-base conversions
+class A { };
+class B : public A { };
+class C : public B { };
+class D : public C { };
+
+int* derived1(A*);
+char* derived1(const A*);
+float* derived1(void*);
+
+int* derived2(A*);
+float* derived2(B*);
+
+int* derived3(A*);
+float* derived3(const B*);
+char* derived3(C*);
+
+void test_derived(B* b, B const* bc, C* c, const C* cc, void* v, D* d) {
+ int* d1 = derived1(b);
+ char* d2 = derived1(bc);
+ int* d3 = derived1(c);
+ char* d4 = derived1(cc);
+ float* d5 = derived1(v);
+
+ float* d6 = derived2(b);
+ float* d7 = derived2(c);
+
+ char* d8 = derived3(d);
+}
More information about the cfe-commits
mailing list