Improve our handling of user-defined conversions as part of overload

resolution. There are two sources of problems involving user-defined
conversions that this change eliminates, along with providing simpler
interfaces for checking implicit conversions:

  - It eliminates a case of infinite recursion found in Boost.

  - It eliminates the search for the constructor needed to copy a temporary
    generated by an implicit conversion from overload
    resolution. Overload resolution assumes that, if it gets a value
    of the parameter's class type (or a derived class thereof), there
    is a way to copy if... even if there isn't. We now model this
    properly.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101680 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-04-17 22:01:05 +00:00
Родитель 4803535dfe
Коммит 3fbaf3e5d5
11 изменённых файлов: 211 добавлений и 94 удалений

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

@ -692,17 +692,20 @@ def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
InGroup<DiagGroup<"uninitialized">>;
def err_temp_copy_no_viable : Error<
"no viable copy constructor %select{copying variable|copying parameter|"
"no viable constructor %select{copying variable|copying parameter|"
"returning object|throwing object|copying member subobject|copying array "
"element}0 of type %1">;
"element|allocating object|copying temporary|initializing base subobject|"
"initializing vector element}0 of type %1">;
def err_temp_copy_ambiguous : Error<
"ambiguous copy constructor call when %select{copying variable|copying "
"ambiguous constructor call when %select{copying variable|copying "
"parameter|returning object|throwing object|copying member subobject|copying "
"array element}0 of type %1">;
"array element|allocating object|copying temporary|initializing base subobject|"
"initializing vector element}0 of type %1">;
def err_temp_copy_deleted : Error<
"%select{copying variable|copying parameter|returning object|throwing "
"object|copying member subobject|copying array element}0 of type %1 invokes "
"deleted copy constructor">;
"object|copying member subobject|copying array element|allocating object|"
"copying temporary|initializing base subobject|initializing vector element}0 "
"of type %1 invokes deleted constructor">;
// C++0x decltype
def err_cannot_determine_declared_type_of_overloaded_function : Error<

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

@ -1064,8 +1064,7 @@ public:
TryImplicitConversion(Expr* From, QualType ToType,
bool SuppressUserConversions,
bool AllowExplicit,
bool InOverloadResolution,
bool UserCast = false);
bool InOverloadResolution);
bool IsStandardConversion(Expr *From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence& SCS);
@ -1090,9 +1089,7 @@ public:
OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
OverloadCandidateSet& Conversions,
bool AllowConversionFunctions,
bool AllowExplicit,
bool UserCast);
bool AllowExplicit);
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);

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

@ -2531,8 +2531,7 @@ static void TryReferenceInitialization(Sema &S,
ImplicitConversionSequence ICS
= S.TryImplicitConversion(Initializer, cv1T1,
/*SuppressUserConversions=*/false, AllowExplicit,
/*FIXME:InOverloadResolution=*/false,
/*UserCast=*/Kind.isExplicitCast());
/*FIXME:InOverloadResolution=*/false);
if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
@ -2867,10 +2866,21 @@ static void TryUserDefinedConversion(Sema &S,
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = Function->getResultType().getNonReferenceType();
Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType);
if (ConvType->getAs<RecordType>()) {
// If we're converting to a class type, there may be an copy if
// the resulting temporary object (possible to create an object of
// a base class type). That copy is not a separate conversion, so
// we just make a note of the actual destination type (possibly a
// base class of the type returned by the conversion function) and
// let the user-defined conversion step handle the conversion.
Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType);
return;
}
// If the conversion following the call to the conversion function is
// interesting, add it as a separate step.
Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType);
// If the conversion following the call to the conversion function
// is interesting, add it as a separate step.
if (Best->FinalConversion.First || Best->FinalConversion.Second ||
Best->FinalConversion.Third) {
ImplicitConversionSequence ICS;
@ -2891,8 +2901,7 @@ static void TryImplicitConversion(Sema &S,
= S.TryImplicitConversion(Initializer, Entity.getType(),
/*SuppressUserConversions=*/true,
/*AllowExplicit=*/false,
/*FIXME:InOverloadResolution=*/false,
/*UserCast=*/Kind.isExplicitCast());
/*InOverloadResolution=*/false);
if (ICS.isBad()) {
Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
@ -3103,10 +3112,11 @@ static Sema::OwningExprResult CopyObject(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Sema::OwningExprResult CurInit) {
// Determine which class type we're copying.
// Determine which class type we're copying to.
Expr *CurInitExpr = (Expr *)CurInit.get();
CXXRecordDecl *Class = 0;
if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
if (const RecordType *Record
= Entity.getType().getNonReferenceType()->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
if (!Class)
return move(CurInit);
@ -3203,16 +3213,26 @@ static Sema::OwningExprResult CopyObject(Sema &S,
return S.ExprError();
}
S.CheckConstructorAccess(Loc,
cast<CXXConstructorDecl>(Best->Function),
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
CurInit.release(); // Ownership transferred into MultiExprArg, below.
// Determine the arguments required to actually perform the
// constructor call (we might have derived-to-base conversions).
if (S.CompleteConstructorCall(Constructor,
Sema::MultiExprArg(S,
(void **)&CurInitExpr,
1),
Loc, ConstructorArgs))
return S.ExprError();
S.CheckConstructorAccess(Loc, Constructor,
Best->FoundDecl.getAccess());
CurInit.release();
return S.BuildCXXConstructExpr(Loc, Entity.getType().getNonReferenceType(),
cast<CXXConstructorDecl>(Best->Function),
Constructor,
Elidable,
Sema::MultiExprArg(S,
(void**)&CurInitExpr, 1));
move_arg(ConstructorArgs));
}
Action::OwningExprResult

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

@ -436,14 +436,11 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) {
/// not permitted.
/// If @p AllowExplicit, then explicit user-defined conversions are
/// permitted.
/// If @p UserCast, the implicit conversion is being done for a user-specified
/// cast.
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr* From, QualType ToType,
bool SuppressUserConversions,
bool AllowExplicit,
bool InOverloadResolution,
bool UserCast) {
bool InOverloadResolution) {
ImplicitConversionSequence ICS;
if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) {
ICS.setStandard();
@ -455,11 +452,47 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
return ICS;
}
if (SuppressUserConversions) {
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
// type is given Exact Match rank, and a conversion of an
// expression of class type to a base class of that type is
// given Conversion rank, in spite of the fact that a copy/move
// constructor (i.e., a user-defined conversion function) is
// called for those cases.
QualType FromType = From->getType();
if (!ToType->getAs<RecordType>() || !FromType->getAs<RecordType>() ||
!(Context.hasSameUnqualifiedType(FromType, ToType) ||
IsDerivedFrom(FromType, ToType))) {
// We're not in the case above, so there is no conversion that
// we can perform.
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
return ICS;
}
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(FromType);
ICS.Standard.setAllToTypes(ToType);
// We don't actually check at this point whether there is a valid
// copy/move constructor, since overloading just assumes that it
// exists. When we actually perform initialization, we'll find the
// appropriate constructor to copy the returned object, if needed.
ICS.Standard.CopyConstructor = 0;
// Determine whether this is considered a derived-to-base conversion.
if (!Context.hasSameUnqualifiedType(FromType, ToType))
ICS.Standard.Second = ICK_Derived_To_Base;
return ICS;
}
// Attempt user-defined conversion.
OverloadCandidateSet Conversions(From->getExprLoc());
OverloadingResult UserDefResult
= IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions,
!SuppressUserConversions, AllowExplicit,
UserCast);
AllowExplicit);
if (UserDefResult == OR_Success) {
ICS.setUserDefined();
@ -1509,45 +1542,39 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
/// and this routine will return true. Otherwise, this routine returns
/// false and User is unspecified.
///
/// \param AllowConversionFunctions true if the conversion should
/// consider conversion functions at all. If false, only constructors
/// will be considered.
///
/// \param AllowExplicit true if the conversion should consider C++0x
/// "explicit" conversion functions as well as non-explicit conversion
/// functions (C++0x [class.conv.fct]p2).
///
/// \param UserCast true if looking for user defined conversion for a static
/// cast.
OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
OverloadCandidateSet& CandidateSet,
bool AllowConversionFunctions,
bool AllowExplicit,
bool UserCast) {
OverloadCandidateSet& CandidateSet,
bool AllowExplicit) {
// Whether we will only visit constructors.
bool ConstructorsOnly = false;
// If the type we are conversion to is a class type, enumerate its
// constructors.
if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
// C++ [over.match.ctor]p1:
// When objects of class type are direct-initialized (8.5), or
// copy-initialized from an expression of the same or a
// derived class type (8.5), overload resolution selects the
// constructor. [...] For copy-initialization, the candidate
// functions are all the converting constructors (12.3.1) of
// that class. The argument list is the expression-list within
// the parentheses of the initializer.
if (Context.hasSameUnqualifiedType(ToType, From->getType()) ||
(From->getType()->getAs<RecordType>() &&
IsDerivedFrom(From->getType(), ToType)))
ConstructorsOnly = true;
if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) {
// We're not going to find any constructors.
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
// C++ [over.match.ctor]p1:
// When objects of class type are direct-initialized (8.5), or
// copy-initialized from an expression of the same or a
// derived class type (8.5), overload resolution selects the
// constructor. [...] For copy-initialization, the candidate
// functions are all the converting constructors (12.3.1) of
// that class. The argument list is the expression-list within
// the parentheses of the initializer.
bool SuppressUserConversions = !UserCast;
if (Context.hasSameUnqualifiedType(ToType, From->getType()) ||
IsDerivedFrom(From->getType(), ToType)) {
SuppressUserConversions = false;
AllowConversionFunctions = false;
}
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ToType).getUnqualifiedType());
Context.getCanonicalType(ToType).getUnqualifiedType());
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd)
= ToRecordDecl->lookup(ConstructorName);
@ -1571,26 +1598,25 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
&From, 1, CandidateSet,
SuppressUserConversions);
/*SuppressUserConversions=*/!ConstructorsOnly);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
AddOverloadCandidate(Constructor, FoundDecl,
&From, 1, CandidateSet,
SuppressUserConversions);
/*SuppressUserConversions=*/!ConstructorsOnly);
}
}
}
}
if (!AllowConversionFunctions) {
// Don't allow any conversion functions to enter the overload set.
// Enumerate conversion functions, if we're allowed to.
if (ConstructorsOnly) {
} else if (RequireCompleteType(From->getLocStart(), From->getType(),
PDiag(0)
<< From->getSourceRange())) {
PDiag(0) << From->getSourceRange())) {
// No conversion functions from incomplete types.
} else if (const RecordType *FromRecordType
= From->getType()->getAs<RecordType>()) {
= From->getType()->getAs<RecordType>()) {
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
@ -1696,7 +1722,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
OverloadCandidateSet CandidateSet(From->getExprLoc());
OverloadingResult OvResult =
IsUserDefinedConversion(From, ToType, ICS.UserDefined,
CandidateSet, true, false, false);
CandidateSet, false);
if (OvResult == OR_Ambiguous)
Diag(From->getSourceRange().getBegin(),
diag::err_typecheck_ambiguous_condition)
@ -1732,16 +1758,10 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// described in 13.3.3.2, the ambiguous conversion sequence is
// treated as a user-defined sequence that is indistinguishable
// from any other user-defined conversion sequence.
if (ICS1.getKind() < ICS2.getKind()) {
if (!(ICS1.isUserDefined() && ICS2.isAmbiguous()))
return ImplicitConversionSequence::Better;
} else if (ICS2.getKind() < ICS1.getKind()) {
if (!(ICS2.isUserDefined() && ICS1.isAmbiguous()))
return ImplicitConversionSequence::Worse;
}
if (ICS1.isAmbiguous() || ICS2.isAmbiguous())
return ImplicitConversionSequence::Indistinguishable;
if (ICS1.getKindRank() < ICS2.getKindRank())
return ImplicitConversionSequence::Better;
else if (ICS2.getKindRank() < ICS1.getKindRank())
return ImplicitConversionSequence::Worse;
// Two implicit conversion sequences of the same form are
// indistinguishable conversion sequences unless one of the
@ -2167,9 +2187,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
}
}
if ((SCS1.ReferenceBinding || SCS1.CopyConstructor) &&
(SCS2.ReferenceBinding || SCS2.CopyConstructor) &&
SCS1.Second == ICK_Derived_To_Base) {
if (SCS1.Second == ICK_Derived_To_Base) {
// -- conversion of C to B is better than conversion of C to A,
// -- binding of an expression of type C to a reference of type
// B& is better than binding an expression of type C to a
@ -3067,7 +3085,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
OverloadCandidateSet& CandidateSet) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
if (!CandidateSet.isNewCandidate(Conversion))
return;
@ -3082,7 +3100,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
Candidate.FinalConversion.setFromType(Conversion->getConversionType());
Candidate.FinalConversion.setFromType(ConvType);
Candidate.FinalConversion.setAllToTypes(ToType);
// Determine the implicit conversion sequence for the implicit
@ -3115,7 +3133,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
return;
}
// To determine what the conversion from the result of calling the
// conversion function to the type we're eventually trying to
// convert to (ToType), we need to synthesize a call to the

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

@ -381,6 +381,33 @@ namespace clang {
assert(isInitialized() && "querying uninitialized conversion");
return Kind(ConversionKind);
}
/// \brief Return a ranking of the implicit conversion sequence
/// kind, where smaller ranks represent better conversion
/// sequences.
///
/// In particular, this routine gives user-defined conversion
/// sequences and ambiguous conversion sequences the same rank,
/// per C++ [over.best.ics]p10.
unsigned getKindRank() const {
switch (getKind()) {
case StandardConversion:
return 0;
case UserDefinedConversion:
case AmbiguousConversion:
return 1;
case EllipsisConversion:
return 2;
case BadConversion:
return 3;
}
return 3;
}
bool isBad() const { return getKind() == BadConversion; }
bool isStandard() const { return getKind() == StandardConversion; }
bool isEllipsis() const { return getKind() == EllipsisConversion; }

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

@ -60,10 +60,10 @@ struct C {
void f() {
A as1[1] = { };
A as2[1] = { 1 }; // expected-error {{copying array element of type 'A' invokes deleted copy constructor}}
A as2[1] = { 1 }; // expected-error {{copying array element of type 'A' invokes deleted constructor}}
B b1 = { };
B b2 = { 1 }; // expected-error {{copying member subobject of type 'A' invokes deleted copy constructor}}
B b2 = { 1 }; // expected-error {{copying member subobject of type 'A' invokes deleted constructor}}
C c1 = { 1 };
}

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

@ -224,7 +224,7 @@ namespace PR6757 {
struct Foo3 {
Foo3();
Foo3(Foo3&);
Foo3(Foo3&); // expected-note{{would lose const qualifier}}
};
struct Bar {
@ -236,7 +236,6 @@ namespace PR6757 {
void f() {
(void)(true ? Bar() : Foo1()); // okay
(void)(true ? Bar() : Foo2()); // okay
// FIXME: Diagnostic below could be improved
(void)(true ? Bar() : Foo3()); // expected-error{{incompatible operand types ('PR6757::Bar' and 'PR6757::Foo3')}}
(void)(true ? Bar() : Foo3()); // expected-error{{no viable constructor copying temporary}}
}
}

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

@ -129,7 +129,7 @@ private:
};
A1 f() {
return "Hello"; // expected-error{{invokes deleted copy constructor}}
return "Hello"; // expected-error{{invokes deleted constructor}}
}
namespace source_locations {
@ -176,3 +176,29 @@ namespace crazy_declarators {
*operator int(); // expected-error {{must use a typedef to declare a conversion to 'int *'}}
};
}
namespace smart_ptr {
class Y {
class YRef { };
Y(Y&);
public:
Y();
Y(YRef);
operator YRef(); // expected-note{{candidate function}}
};
struct X { // expected-note{{candidate constructor (the implicit copy constructor) not}}
explicit X(Y);
};
Y make_Y();
X f() {
X x = make_Y(); // expected-error{{no viable conversion from 'smart_ptr::Y' to 'smart_ptr::X'}}
X x2(make_Y());
return X(Y());
}
}

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

@ -25,19 +25,17 @@ void test(const foo *P) { P->bar(); } // expected-error{{cannot initialize objec
namespace PR6757 {
struct Foo {
Foo();
Foo(Foo&);
Foo(Foo&); // expected-note{{candidate constructor not viable}}
};
struct Bar {
operator const Foo&() const;
};
void f(Foo); // expected-note{{candidate function not viable: no known conversion from 'PR6757::Bar' to 'PR6757::Foo' for 1st argument}}
void f(Foo);
// FIXME: This isn't really the right reason for the failure. We
// should fail after overload resolution.
void g(Foo foo) {
f(Bar()); // expected-error{{no matching function for call to 'f'}}
f(Bar()); // expected-error{{no viable constructor copying parameter of type 'PR6757::Foo const'}}
f(foo);
}
}

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

@ -67,3 +67,18 @@ void test_conversion(ConvertibleToBase ctb, ConvertibleToDerived ctd,
Base b4(ctd);
Base b5 = ctfd;
}
struct X1 {
X1(X1&); // expected-note{{candidate constructor not viable: no known conversion from 'X1' to 'X1 &' for 1st argument}}
};
struct X2 {
operator X1();
};
int &f(X1);
float &f(...);
void g(X2 b) {
int &ir = f(b); // expected-error{{no viable constructor copying parameter of type 'X1'}}
}

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

@ -94,3 +94,18 @@ void default_ctor_inst() {
}
template void default_ctor_inst<int>();
template<typename T>
struct X5 {
X5();
X5(const T &);
};
struct X6 {
template<typename T> X6(T);
};
void test_X5_X6() {
X5<X6> tf;
X5<X6> tf2(tf);
}