зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
4803535dfe
Коммит
3fbaf3e5d5
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче