Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -3981,16 +3981,13 @@ return Ctx.hasSameUnqualifiedType(ParmT, ClassT); } -static OverloadingResult -ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, - MultiExprArg Args, - OverloadCandidateSet &CandidateSet, - QualType DestType, - DeclContext::lookup_result Ctors, - OverloadCandidateSet::iterator &Best, - bool CopyInitializing, bool AllowExplicit, - bool OnlyListConstructors, bool IsListInit, - bool SecondStepOfCopyInit = false) { +static OverloadingResult ResolveConstructorOverload( + Sema &S, SourceLocation DeclLoc, MultiExprArg Args, + OverloadCandidateSet &CandidateSet, QualType DestType, + DeclContext::lookup_result Ctors, OverloadCandidateSet::iterator &Best, + bool CopyInitializing, bool AllowExplicit, bool OnlyListConstructors, + bool IsListInit, bool RequireActualConstructor, + bool SecondStepOfCopyInit = false) { CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor); CandidateSet.setDestAS(DestType.getQualifiers().getAddressSpace()); @@ -4053,7 +4050,7 @@ // Note: SecondStepOfCopyInit is only ever true in this case when // evaluating whether to produce a C++98 compatibility warning. if (S.getLangOpts().CPlusPlus17 && Args.size() == 1 && - !SecondStepOfCopyInit) { + !RequireActualConstructor && !SecondStepOfCopyInit) { Expr *Initializer = Args[0]; auto *SourceRD = Initializer->getType()->getAsCXXRecordDecl(); if (SourceRD && S.isCompleteType(DeclLoc, Initializer->getType())) { @@ -4121,6 +4118,12 @@ return; } + bool RequireActualConstructor = + !(Entity.getKind() != InitializedEntity::EK_Base && + Entity.getKind() != InitializedEntity::EK_Delegating && + Entity.getKind() != + InitializedEntity::EK_LambdaToBlockConversionBlockElement); + // C++17 [dcl.init]p17: // - If the initializer expression is a prvalue and the cv-unqualified // version of the source type is the same class as the class of the @@ -4130,11 +4133,7 @@ // class or delegating to another constructor from a mem-initializer. // ObjC++: Lambda captured by the block in the lambda to block conversion // should avoid copy elision. - if (S.getLangOpts().CPlusPlus17 && - Entity.getKind() != InitializedEntity::EK_Base && - Entity.getKind() != InitializedEntity::EK_Delegating && - Entity.getKind() != - InitializedEntity::EK_LambdaToBlockConversionBlockElement && + if (S.getLangOpts().CPlusPlus17 && !RequireActualConstructor && UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isPRValue() && S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) { // Convert qualifications if necessary. @@ -4182,11 +4181,10 @@ // If the initializer list has no elements and T has a default constructor, // the first phase is omitted. if (!(UnwrappedArgs.empty() && S.LookupDefaultConstructor(DestRecordDecl))) - Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, - CandidateSet, DestType, Ctors, Best, - CopyInitialization, AllowExplicit, - /*OnlyListConstructors=*/true, - IsListInit); + Result = ResolveConstructorOverload( + S, Kind.getLocation(), Args, CandidateSet, DestType, Ctors, Best, + CopyInitialization, AllowExplicit, + /*OnlyListConstructors=*/true, IsListInit, RequireActualConstructor); } // C++11 [over.match.list]p1: @@ -4196,11 +4194,10 @@ // elements of the initializer list. if (Result == OR_No_Viable_Function) { AsInitializerList = false; - Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs, - CandidateSet, DestType, Ctors, Best, - CopyInitialization, AllowExplicit, - /*OnlyListConstructors=*/false, - IsListInit); + Result = ResolveConstructorOverload( + S, Kind.getLocation(), UnwrappedArgs, CandidateSet, DestType, Ctors, + Best, CopyInitialization, AllowExplicit, + /*OnlyListConstructors=*/false, IsListInit, RequireActualConstructor); } if (Result) { Sequence.SetOverloadFailure( @@ -6608,6 +6605,7 @@ S, Loc, CurInitExpr, CandidateSet, T, Ctors, Best, /*CopyInitializing=*/false, /*AllowExplicit=*/true, /*OnlyListConstructors=*/false, /*IsListInit=*/false, + /*RequireActualConstructor=*/false, /*SecondStepOfCopyInit=*/true)) { case OR_Success: break; @@ -6753,6 +6751,7 @@ S, Loc, CurInitExpr, CandidateSet, CurInitExpr->getType(), Ctors, Best, /*CopyInitializing=*/false, /*AllowExplicit=*/true, /*OnlyListConstructors=*/false, /*IsListInit=*/false, + /*RequireActualConstructor=*/false, /*SecondStepOfCopyInit=*/true); PartialDiagnostic Diag = S.PDiag(diag::warn_cxx98_compat_temp_copy) Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -740,6 +740,10 @@ Diags.Report(Active->PointOfInstantiation, diag::note_template_nsdmi_here) << FD << Active->InstantiationRange; + } else if (ClassTemplateDecl *CTD = dyn_cast(D)) { + Diags.Report(Active->PointOfInstantiation, + diag::note_template_class_instantiation_here) + << CTD << Active->InstantiationRange; } else { Diags.Report(Active->PointOfInstantiation, diag::note_template_type_alias_instantiation_here) Index: clang/test/SemaCXX/cxx1z-copy-omission.cpp =================================================================== --- clang/test/SemaCXX/cxx1z-copy-omission.cpp +++ clang/test/SemaCXX/cxx1z-copy-omission.cpp @@ -171,3 +171,29 @@ Foo f(Derived d) { return d; } // expected-error {{invokes a deleted function}} Foo g(Derived d) { return Foo(d); } // ok, calls constructor } + +// Make sure we don't consider conversion functions for guaranteed copy elision +namespace GH39319 { +struct A { + A(); +}; +struct B { + operator A(); +} C; +A::A() : A(C) {} + +struct A2 { + struct B2 { + operator A2(); + }; + A2() : A2(B2()) {} +}; + +template +class B3 : A3 // expected-error {{expected '{' after base class list}} + template()> // expected-warning 2{{use of function template name with no prior declaration in function call with explicit}} + B3() // expected-error {{expected ';' at end of declaration list}} +} B3(); // expected-error {{expected ';' after class}} \ + // expected-error {{deduction guide declaration without trailing return type}} \ + // expected-note {{in instantiation of template class}} +}