[cfe-commits] r62971 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaType.cpp test/SemaCXX/member-pointer.cpp test/SemaCXX/qualification-conversion.cpp
Sebastian Redl
sebastian.redl at getdesigned.at
Sun Jan 25 11:43:22 PST 2009
Author: cornedbee
Date: Sun Jan 25 13:43:20 2009
New Revision: 62971
URL: http://llvm.org/viewvc/llvm-project?rev=62971&view=rev
Log:
Implement implicit conversions for pointers-to-member.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/SemaCXX/member-pointer.cpp
cfe/trunk/test/SemaCXX/qualification-conversion.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=62971&r1=62970&r2=62971&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Sun Jan 25 13:43:20 2009
@@ -1590,6 +1590,12 @@
// FIXME: better way to display derivation? Pass entire thing into diagclient?
DIAG(err_ambiguous_derived_to_base_conv, ERROR,
"ambiguous conversion from derived class %0 to base class %1:%2")
+DIAG(err_ambiguous_base_to_derived_memptr_conv, ERROR,
+ "ambiguous conversion from pointer to member of base class %0 "
+ "to pointer to member of derived class %1:%2")
+DIAG(err_memptr_conv_via_virtual, ERROR,
+ "conversion from pointer to member of class %0 to pointer to member "
+ "of class %1 via virtual base %2 is not allowed")
// C++ member name lookup
DIAG(err_ambiguous_member_multiple_subobjects, ERROR,
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=62971&r1=62970&r2=62971&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sun Jan 25 13:43:20 2009
@@ -428,6 +428,9 @@
bool isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType, bool &IncompatibleObjC);
bool CheckPointerConversion(Expr *From, QualType ToType);
+ bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
+ QualType &ConvertedType);
+ bool CheckMemberPointerConversion(Expr *From, QualType ToType);
bool IsQualificationConversion(QualType FromType, QualType ToType);
bool IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=62971&r1=62970&r2=62971&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sun Jan 25 13:43:20 2009
@@ -832,8 +832,9 @@
break;
case ICK_Pointer_Member:
- // FIXME: Implement pointer-to-member conversions.
- assert(false && "Pointer-to-member conversions are unsupported");
+ if (CheckMemberPointerConversion(From, ToType))
+ return true;
+ ImpCastExprToType(From, ToType);
break;
case ICK_Boolean_Conversion:
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=62971&r1=62970&r2=62971&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Jan 25 13:43:20 2009
@@ -544,14 +544,17 @@
SCS.Second = ICK_Pointer_Conversion;
SCS.IncompatibleObjC = IncompatibleObjC;
}
- // FIXME: Pointer to member conversions (4.11).
+ // Pointer to member conversions (4.11).
+ else if (IsMemberPointerConversion(From, FromType, ToType, FromType)) {
+ SCS.Second = ICK_Pointer_Member;
+ }
// Boolean conversions (C++ 4.12).
- // FIXME: pointer-to-member type
else if (ToType->isBooleanType() &&
(FromType->isArithmeticType() ||
FromType->isEnumeralType() ||
FromType->isPointerType() ||
- FromType->isBlockPointerType())) {
+ FromType->isBlockPointerType() ||
+ FromType->isMemberPointerType())) {
SCS.Second = ICK_Boolean_Conversion;
FromType = Context.BoolTy;
} else {
@@ -999,7 +1002,7 @@
}
}
- return false;
+ return false;
}
/// CheckPointerConversion - Check the pointer conversion from the
@@ -1013,8 +1016,6 @@
if (const PointerType *FromPtrType = FromType->getAsPointerType())
if (const PointerType *ToPtrType = ToType->getAsPointerType()) {
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
- /*DetectVirtual=*/false);
QualType FromPointeeType = FromPtrType->getPointeeType(),
ToPointeeType = ToPtrType->getPointeeType();
@@ -1040,6 +1041,100 @@
return false;
}
+/// IsMemberPointerConversion - Determines whether the conversion of the
+/// expression From, which has the (possibly adjusted) type FromType, can be
+/// converted to the type ToType via a member pointer conversion (C++ 4.11).
+/// If so, returns true and places the converted type (that might differ from
+/// ToType in its cv-qualifiers at some level) into ConvertedType.
+bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
+ QualType ToType, QualType &ConvertedType)
+{
+ const MemberPointerType *ToTypePtr = ToType->getAsMemberPointerType();
+ if (!ToTypePtr)
+ return false;
+
+ // A null pointer constant can be converted to a member pointer (C++ 4.11p1)
+ if (From->isNullPointerConstant(Context)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
+ // Otherwise, both types have to be member pointers.
+ const MemberPointerType *FromTypePtr = FromType->getAsMemberPointerType();
+ if (!FromTypePtr)
+ return false;
+
+ // A pointer to member of B can be converted to a pointer to member of D,
+ // where D is derived from B (C++ 4.11p2).
+ QualType FromClass(FromTypePtr->getClass(), 0);
+ QualType ToClass(ToTypePtr->getClass(), 0);
+ // FIXME: What happens when these are dependent? Is this function even called?
+
+ if (IsDerivedFrom(ToClass, FromClass)) {
+ ConvertedType = Context.getMemberPointerType(FromTypePtr->getPointeeType(),
+ ToClass.getTypePtr());
+ return true;
+ }
+
+ return false;
+}
+
+/// CheckMemberPointerConversion - Check the member pointer conversion from the
+/// expression From to the type ToType. This routine checks for ambiguous or
+/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions
+/// for which IsMemberPointerConversion has already returned true. It returns
+/// true and produces a diagnostic if there was an error, or returns false
+/// otherwise.
+bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) {
+ QualType FromType = From->getType();
+
+ if (const MemberPointerType *FromPtrType =
+ FromType->getAsMemberPointerType()) {
+ if (const MemberPointerType *ToPtrType =
+ ToType->getAsMemberPointerType()) {
+ QualType FromClass = QualType(FromPtrType->getClass(), 0);
+ QualType ToClass = QualType(ToPtrType->getClass(), 0);
+
+ // FIXME: What about dependent types?
+ assert(FromClass->isRecordType() && "Pointer into non-class.");
+ assert(ToClass->isRecordType() && "Pointer into non-class.");
+
+ BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/true);
+ bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
+ assert(DerivationOkay &&
+ "Should not have been called if derivation isn't OK.");
+ if (!DerivationOkay)
+ return true;
+
+ if (Paths.isAmbiguous(Context.getCanonicalType(FromClass).
+ getUnqualifiedType())) {
+ // Derivation is ambiguous. Redo the check to find the exact paths.
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths);
+ assert(StillOkay && "Derivation changed due to quantum fluctuation.");
+ if (!StillOkay)
+ return true;
+
+ std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
+ Diag(From->getExprLoc(),
+ diag::err_ambiguous_base_to_derived_memptr_conv)
+ << FromClass << ToClass << PathDisplayStr << From->getSourceRange();
+ return true;
+ }
+
+ if (const CXXRecordType *VBase = Paths.getDetectedVirtual()) {
+ Diag(From->getExprLoc(), diag::err_memptr_conv_via_virtual)
+ << FromClass << ToClass << QualType(VBase, 0)
+ << From->getSourceRange();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
/// IsQualificationConversion - Determines whether the conversion from
/// an rvalue of type FromType to ToType is a qualification conversion
/// (C++ 4.4).
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=62971&r1=62970&r2=62971&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sun Jan 25 13:43:20 2009
@@ -561,7 +561,8 @@
DeclType.Mem.TypeQuals &= ~QualType::Restrict;
}
- T = Context.getMemberPointerType(T, ClsType.getTypePtr());
+ T = Context.getMemberPointerType(T, ClsType.getTypePtr()).
+ getQualifiedType(DeclType.Mem.TypeQuals);
break;
}
@@ -660,7 +661,13 @@
return true;
}
- // FIXME: pointer-to-member types
+ const MemberPointerType *T1MPType = T1->getAsMemberPointerType(),
+ *T2MPType = T2->getAsMemberPointerType();
+ if (T1MPType && T2MPType) {
+ T1 = T1MPType->getPointeeType();
+ T2 = T2MPType->getPointeeType();
+ return true;
+ }
return false;
}
Modified: cfe/trunk/test/SemaCXX/member-pointer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-pointer.cpp?rev=62971&r1=62970&r2=62971&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/member-pointer.cpp (original)
+++ cfe/trunk/test/SemaCXX/member-pointer.cpp Sun Jan 25 13:43:20 2009
@@ -3,6 +3,7 @@
struct A {};
enum B { Dummy };
namespace C {}
+struct D : A {};
int A::*pdi1;
int (::A::*pdi2);
@@ -16,4 +17,16 @@
void f() {
// This requires tentative parsing.
int (A::*pf)(int, int);
+
+ // Implicit conversion to bool.
+ bool b = pdi1;
+ b = pfi;
+
+ // Conversion from null pointer constant.
+ pf = 0;
+ pf = __null;
+
+ // Conversion to member of derived.
+ int D::*pdid = pdi1;
+ pdid = pdi2;
}
Modified: cfe/trunk/test/SemaCXX/qualification-conversion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/qualification-conversion.cpp?rev=62971&r1=62970&r2=62971&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/qualification-conversion.cpp (original)
+++ cfe/trunk/test/SemaCXX/qualification-conversion.cpp Sun Jan 25 13:43:20 2009
@@ -9,3 +9,15 @@
quals2(pp);
quals3(ppp); // expected-error {{ incompatible type passing 'int ***', expected 'int const **const *' }}
}
+
+struct A {};
+void mquals1(int const A::*p);
+void mquals2(int const A::* const A::*pp);
+void mquals3(int const A::* A::* const A::*ppp);
+
+void test_mquals(int A::*p, int A::* A::*pp, int A::* A::* A::*ppp) {
+ int const A::* const A::* pp2 = pp;
+ mquals1(p);
+ mquals2(pp);
+ mquals3(ppp); // expected-error {{ incompatible type passing 'int struct A::*struct A::*struct A::*', expected 'int const struct A::*struct A::*const struct A::*' }}
+}
More information about the cfe-commits
mailing list