diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 15 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 7 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 50 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 131 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 27 | ||||
-rw-r--r-- | test/SemaCXX/aggregate-initialization.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/conditional-expr.cpp | 5 | ||||
-rw-r--r-- | test/SemaCXX/conversion-function.cpp | 28 | ||||
-rw-r--r-- | test/SemaCXX/copy-initialization.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/user-defined-conversions.cpp | 15 | ||||
-rw-r--r-- | test/SemaTemplate/constructor-template.cpp | 15 |
11 files changed, 211 insertions, 94 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f2ab414b39..ba8008d0b6 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 2d5cee43e6..ef76882ac0 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 76de0729b5..4986fcbedf 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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 diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index c4a42cd1ef..11fc972ee2 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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 diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 2b9604ac14..5e61111308 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -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; } diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp index 708a8f256a..81a0e6f744 100644 --- a/test/SemaCXX/aggregate-initialization.cpp +++ b/test/SemaCXX/aggregate-initialization.cpp @@ -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 }; } diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp index cb78a2e65f..aa41323239 100644 --- a/test/SemaCXX/conditional-expr.cpp +++ b/test/SemaCXX/conditional-expr.cpp @@ -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}} } } diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp index 972409ca5a..dfc0650641 100644 --- a/test/SemaCXX/conversion-function.cpp +++ b/test/SemaCXX/conversion-function.cpp @@ -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()); + } +} diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp index e5b1fd766b..ea67e6ffe2 100644 --- a/test/SemaCXX/copy-initialization.cpp +++ b/test/SemaCXX/copy-initialization.cpp @@ -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); } } diff --git a/test/SemaCXX/user-defined-conversions.cpp b/test/SemaCXX/user-defined-conversions.cpp index 4367f4b8a3..5de7f44be9 100644 --- a/test/SemaCXX/user-defined-conversions.cpp +++ b/test/SemaCXX/user-defined-conversions.cpp @@ -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'}} +} diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp index 82c2aa4cc3..b6ca72e9e1 100644 --- a/test/SemaTemplate/constructor-template.cpp +++ b/test/SemaTemplate/constructor-template.cpp @@ -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); +} |