Implement overloading rules for reference binding

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58381 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2008-10-29 14:50:44 +00:00
Родитель a206b0614a
Коммит f70bdb9463
4 изменённых файлов: 136 добавлений и 30 удалений

Просмотреть файл

@ -785,8 +785,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
ICS->Standard.Third = ICK_Identity;
ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
ICS->ReferenceBinding = true;
ICS->DirectBinding = true;
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = true;
// Nothing more to do: the inaccessibility/ambiguity check for
// derived-to-base conversions is suppressed when we're
@ -876,8 +876,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
ICS->Standard.Third = ICK_Identity;
ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
ICS->ReferenceBinding = true;
ICS->DirectBinding = false;
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = false;
} else {
// FIXME: Binding to a subobject of the rvalue is going to require
// more AST annotation than this.

Просмотреть файл

@ -471,7 +471,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType)
ICS.Standard.Third = ICK_Identity;
// C++ [dcl.init]p14 last bullet:
// Note: an expression of type "cv1 T" can initialize an object
// [ Note: an expression of type "cv1 T" can initialize an object
// of type “cv2 T” independently of the cv-qualifiers cv1 and
// cv2. -- end note]
//
@ -877,21 +877,48 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// 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*.
// conversion of B* to A* is better than conversion of B* to
// void*, and 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)
if (SCS1ConvertsToVoid != SCS2ConvertsToVoid) {
// Exactly one of the conversion sequences is a conversion to
// a void pointer; it's the worse conversion.
return SCS2ConvertsToVoid ? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
if (!SCS1ConvertsToVoid && !SCS2ConvertsToVoid)
} else if (!SCS1ConvertsToVoid && !SCS2ConvertsToVoid) {
// Neither conversion sequence converts to a void pointer; compare
// their derived-to-base conversions.
if (ImplicitConversionSequence::CompareKind DerivedCK
= CompareDerivedToBaseConversions(SCS1, SCS2))
return DerivedCK;
} else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid) {
// Both conversion sequences are conversions to void
// pointers. Compare the source types to determine if there's an
// inheritance relationship in their sources.
QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr);
QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr);
// 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);
QualType FromPointee1
= FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
QualType FromPointee2
= FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
if (IsDerivedFrom(FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
}
// Compare based on qualification conversions (C++ 13.3.3.2p3,
// bullet 3).
@ -899,7 +926,24 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
= CompareQualificationConversions(SCS1, SCS2))
return QualCK;
// FIXME: Handle comparison of reference bindings.
// C++ [over.ics.rank]p3b4:
// -- S1 and S2 are reference bindings (8.5.3), and the types to
// which the references refer are the same type except for
// top-level cv-qualifiers, and the type to which the reference
// initialized by S2 refers is more cv-qualified than the type
// to which the reference initialized by S1 refers.
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) {
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
else if (T1.isMoreQualifiedThan(T2))
return ImplicitConversionSequence::Worse;
}
}
return ImplicitConversionSequence::Indistinguishable;
}
@ -1018,16 +1062,14 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
FromType2 = Context.getCanonicalType(FromType2);
ToType2 = Context.getCanonicalType(ToType2);
// C++ [over.ics.rank]p4b4:
// C++ [over.ics.rank]p4b3:
//
// 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.
// Compare based on pointer conversions.
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
@ -1036,16 +1078,60 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
= FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
QualType ToPointee2
= ToType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
if (IsDerivedFrom(ToPointee1, ToPointee2))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(ToPointee2, ToPointee1))
return ImplicitConversionSequence::Worse;
}
// -- conversion of B* to A* is better than conversion of C* to A*,
if (FromPointee1 != FromPointee2 && ToPointee1 == ToPointee2) {
if (IsDerivedFrom(FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
}
}
// FIXME: many more sub-bullets of C++ [over.ics.rank]p4b4 to
// implement.
// Compare based on reference bindings.
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding &&
SCS1.Second == ICK_Derived_To_Base) {
// -- binding of an expression of type C to a reference of type
// B& is better than binding an expression of type C to a
// reference of type A&,
if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() &&
ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) {
if (IsDerivedFrom(ToType1, ToType2))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(ToType2, ToType1))
return ImplicitConversionSequence::Worse;
}
// -- binding of an expression of type B to a reference of type
// A& is better than binding an expression of type C to a
// reference of type A&,
if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
if (IsDerivedFrom(FromType2, FromType1))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromType1, FromType2))
return ImplicitConversionSequence::Worse;
}
}
// FIXME: conversion of A::* to B::* is better than conversion of
// A::* to C::*,
// FIXME: conversion of B::* to C::* is better than conversion of
// A::* to C::*, and
// FIXME: conversion of C to B is better than conversion of C to A,
// FIXME: conversion of B to A is better than conversion of C to A.
return ImplicitConversionSequence::Indistinguishable;
}

Просмотреть файл

@ -97,6 +97,14 @@ namespace clang {
/// (C++ 4.2p2).
bool Deprecated : 1;
/// ReferenceBinding - True when this is a reference binding
/// (C++ [over.ics.ref]).
bool ReferenceBinding : 1;
/// DirectBinding - True when this is a reference binding that is a
/// direct binding (C++ [dcl.init.ref]).
bool DirectBinding : 1;
/// FromType - The type that this conversion is converting
/// from. This is an opaque pointer that can be translated into a
/// QualType.
@ -155,17 +163,7 @@ namespace clang {
};
/// ConversionKind - The kind of implicit conversion sequence.
/// As usual, we use "unsigned" here because VC++ makes enum bitfields
/// signed.
unsigned ConversionKind : 2;
/// ReferenceBinding - True when this is a reference binding
/// (C++ [over.ics.ref]).
bool ReferenceBinding : 1;
/// DirectBinding - True when this is a reference binding that is a
/// direct binding (C++ [dcl.init.ref]).
bool DirectBinding : 1;
Kind ConversionKind;
union {
/// When ConversionKind == StandardConversion, provides the

Просмотреть файл

@ -253,3 +253,25 @@ void cvqual_subsume_test(Z z) {
cvqual_subsume(z); // expected-error{{call to 'cvqual_subsume' is ambiguous; candidates are:}}
int& x = cvqual_subsume2(get_Z()); // okay: only binds to the first one
}
// Test overloading with cv-qualification differences in reference
// binding.
int& cvqual_diff(X&);
float& cvqual_diff(const X&);
void cvqual_diff_test(X x, Z z) {
int& i1 = cvqual_diff(x);
int& i2 = cvqual_diff(z);
}
// Test overloading with derived-to-base differences in reference
// binding.
struct Z2 : Z { };
int& db_rebind(X&);
long& db_rebind(Y&);
float& db_rebind(Z&);
void db_rebind_test(Z2 z2) {
float& f1 = db_rebind(z2);
}