зеркало из https://github.com/microsoft/clang-1.git
Implement implicit conversions for pointers-to-member.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62971 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
424c51d3d4
Коммит
4433aafbc2
|
@ -1590,6 +1590,12 @@ DIAG(err_duplicate_base_class, ERROR,
|
||||||
// FIXME: better way to display derivation? Pass entire thing into diagclient?
|
// FIXME: better way to display derivation? Pass entire thing into diagclient?
|
||||||
DIAG(err_ambiguous_derived_to_base_conv, ERROR,
|
DIAG(err_ambiguous_derived_to_base_conv, ERROR,
|
||||||
"ambiguous conversion from derived class %0 to base class %1:%2")
|
"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
|
// C++ member name lookup
|
||||||
DIAG(err_ambiguous_member_multiple_subobjects, ERROR,
|
DIAG(err_ambiguous_member_multiple_subobjects, ERROR,
|
||||||
|
|
|
@ -428,6 +428,9 @@ public:
|
||||||
bool isObjCPointerConversion(QualType FromType, QualType ToType,
|
bool isObjCPointerConversion(QualType FromType, QualType ToType,
|
||||||
QualType& ConvertedType, bool &IncompatibleObjC);
|
QualType& ConvertedType, bool &IncompatibleObjC);
|
||||||
bool CheckPointerConversion(Expr *From, QualType ToType);
|
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 IsQualificationConversion(QualType FromType, QualType ToType);
|
||||||
bool IsUserDefinedConversion(Expr *From, QualType ToType,
|
bool IsUserDefinedConversion(Expr *From, QualType ToType,
|
||||||
UserDefinedConversionSequence& User,
|
UserDefinedConversionSequence& User,
|
||||||
|
|
|
@ -832,8 +832,9 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ICK_Pointer_Member:
|
case ICK_Pointer_Member:
|
||||||
// FIXME: Implement pointer-to-member conversions.
|
if (CheckMemberPointerConversion(From, ToType))
|
||||||
assert(false && "Pointer-to-member conversions are unsupported");
|
return true;
|
||||||
|
ImpCastExprToType(From, ToType);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ICK_Boolean_Conversion:
|
case ICK_Boolean_Conversion:
|
||||||
|
|
|
@ -544,14 +544,17 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
|
||||||
SCS.Second = ICK_Pointer_Conversion;
|
SCS.Second = ICK_Pointer_Conversion;
|
||||||
SCS.IncompatibleObjC = IncompatibleObjC;
|
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).
|
// Boolean conversions (C++ 4.12).
|
||||||
// FIXME: pointer-to-member type
|
|
||||||
else if (ToType->isBooleanType() &&
|
else if (ToType->isBooleanType() &&
|
||||||
(FromType->isArithmeticType() ||
|
(FromType->isArithmeticType() ||
|
||||||
FromType->isEnumeralType() ||
|
FromType->isEnumeralType() ||
|
||||||
FromType->isPointerType() ||
|
FromType->isPointerType() ||
|
||||||
FromType->isBlockPointerType())) {
|
FromType->isBlockPointerType() ||
|
||||||
|
FromType->isMemberPointerType())) {
|
||||||
SCS.Second = ICK_Boolean_Conversion;
|
SCS.Second = ICK_Boolean_Conversion;
|
||||||
FromType = Context.BoolTy;
|
FromType = Context.BoolTy;
|
||||||
} else {
|
} else {
|
||||||
|
@ -999,7 +1002,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CheckPointerConversion - Check the pointer conversion from the
|
/// CheckPointerConversion - Check the pointer conversion from the
|
||||||
|
@ -1013,8 +1016,6 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) {
|
||||||
|
|
||||||
if (const PointerType *FromPtrType = FromType->getAsPointerType())
|
if (const PointerType *FromPtrType = FromType->getAsPointerType())
|
||||||
if (const PointerType *ToPtrType = ToType->getAsPointerType()) {
|
if (const PointerType *ToPtrType = ToType->getAsPointerType()) {
|
||||||
BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
|
|
||||||
/*DetectVirtual=*/false);
|
|
||||||
QualType FromPointeeType = FromPtrType->getPointeeType(),
|
QualType FromPointeeType = FromPtrType->getPointeeType(),
|
||||||
ToPointeeType = ToPtrType->getPointeeType();
|
ToPointeeType = ToPtrType->getPointeeType();
|
||||||
|
|
||||||
|
@ -1040,6 +1041,100 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) {
|
||||||
return false;
|
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
|
/// IsQualificationConversion - Determines whether the conversion from
|
||||||
/// an rvalue of type FromType to ToType is a qualification conversion
|
/// an rvalue of type FromType to ToType is a qualification conversion
|
||||||
/// (C++ 4.4).
|
/// (C++ 4.4).
|
||||||
|
|
|
@ -561,7 +561,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
|
||||||
DeclType.Mem.TypeQuals &= ~QualType::Restrict;
|
DeclType.Mem.TypeQuals &= ~QualType::Restrict;
|
||||||
}
|
}
|
||||||
|
|
||||||
T = Context.getMemberPointerType(T, ClsType.getTypePtr());
|
T = Context.getMemberPointerType(T, ClsType.getTypePtr()).
|
||||||
|
getQualifiedType(DeclType.Mem.TypeQuals);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -660,7 +661,13 @@ bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2)
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
struct A {};
|
struct A {};
|
||||||
enum B { Dummy };
|
enum B { Dummy };
|
||||||
namespace C {}
|
namespace C {}
|
||||||
|
struct D : A {};
|
||||||
|
|
||||||
int A::*pdi1;
|
int A::*pdi1;
|
||||||
int (::A::*pdi2);
|
int (::A::*pdi2);
|
||||||
|
@ -16,4 +17,16 @@ int& A::*pdr; // expected-error {{'pdr' declared as a pointer to a reference}}
|
||||||
void f() {
|
void f() {
|
||||||
// This requires tentative parsing.
|
// This requires tentative parsing.
|
||||||
int (A::*pf)(int, int);
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,3 +9,15 @@ void test_quals(int * p, int * * pp, int * * * ppp) {
|
||||||
quals2(pp);
|
quals2(pp);
|
||||||
quals3(ppp); // expected-error {{ incompatible type passing 'int ***', expected 'int const **const *' }}
|
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::*' }}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче