From 4d9b1ce096b305a4a0ba489c3b44d641f14956cd Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 26 Sep 2017 18:37:55 +0000 Subject: [PATCH] Resolve a defect in C++17 copy omission. When selecting constructors for initializing an object of type T from a single expression of class type U, also consider conversion functions of U that convert to T (rather than modeling such conversions as calling a conversion function and then calling a constructor). This approach is proposed as the resolution for the defect, and is also already implemented by GCC. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314231 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Overload.h | 30 ++++++---- include/clang/Sema/Sema.h | 6 +- lib/Sema/SemaCodeComplete.cpp | 3 +- lib/Sema/SemaInit.cpp | 87 +++++++++++++++++++++++----- lib/Sema/SemaOverload.cpp | 86 +++++++++++++++++---------- test/SemaCXX/cxx1z-copy-omission.cpp | 32 +++++++++- 6 files changed, 186 insertions(+), 58 deletions(-) diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index ffdf011d1d..05cfe53666 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -726,11 +726,20 @@ namespace clang { enum CandidateSetKind { /// Normal lookup. CSK_Normal, - /// Lookup for candidates for a call using operator syntax. Candidates - /// that have no parameters of class type will be skipped unless there - /// is a parameter of (reference to) enum type and the corresponding - /// argument is of the same enum type. - CSK_Operator + /// C++ [over.match.oper]: + /// Lookup of operator function candidates in a call using operator + /// syntax. Candidates that have no parameters of class type will be + /// skipped unless there is a parameter of (reference to) enum type and + /// the corresponding argument is of the same enum type. + CSK_Operator, + /// C++ [over.match.copy]: + /// Copy-initialization of an object of class type by user-defined + /// conversion. + CSK_InitByUserDefinedConversion, + /// C++ [over.match.ctor], [over.match.list] + /// Initialization of an object of class type by constructor, + /// using either a parenthesized or braced list of arguments. + CSK_InitByConstructor, }; private: @@ -795,7 +804,7 @@ namespace clang { } /// \brief Clear out all of the candidates. - void clear(); + void clear(CandidateSetKind CSK); typedef SmallVectorImpl::iterator iterator; iterator begin() { return Candidates.begin(); } @@ -835,8 +844,7 @@ namespace clang { /// Find the best viable function on this overload set, if it exists. OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, - OverloadCandidateSet::iterator& Best, - bool UserDefinedConversion = false); + OverloadCandidateSet::iterator& Best); void NoteCandidates(Sema &S, OverloadCandidateDisplayKind OCD, @@ -848,10 +856,10 @@ namespace clang { }; bool isBetterOverloadCandidate(Sema &S, - const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2, + const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2, SourceLocation Loc, - bool UserDefinedConversion = false); + OverloadCandidateSet::CandidateSetKind Kind); struct ConstructorInfo { DeclAccessPair FoundDecl; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0f2729eb87..e7f6fbcdab 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2742,13 +2742,15 @@ public: CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet, - bool AllowObjCConversionOnExplicit); + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion = true); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, - bool AllowObjCConversionOnExplicit); + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion = true); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index d3138a9650..90a15e17a2 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4293,7 +4293,8 @@ static void mergeCandidatesWithResults(Sema &SemaRef, std::stable_sort( CandidateSet.begin(), CandidateSet.end(), [&](const OverloadCandidate &X, const OverloadCandidate &Y) { - return isBetterOverloadCandidate(SemaRef, X, Y, Loc); + return isBetterOverloadCandidate(SemaRef, X, Y, Loc, + CandidateSet.getKind()); }); // Add the remaining viable overload candidates as code-completion results. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 8aa60bcef0..59ec9e2851 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -3531,12 +3531,13 @@ 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) { - CandidateSet.clear(); + CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor); for (NamedDecl *D : Ctors) { auto Info = getConstructorInfo(D); @@ -3587,6 +3588,50 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, } } + // FIXME: Work around a bug in C++17 guaranteed copy elision. + // + // When initializing an object of class type T by constructor + // ([over.match.ctor]) or by list-initialization ([over.match.list]) + // from a single expression of class type U, conversion functions of + // U that convert to the non-reference type cv T are candidates. + // Explicit conversion functions are only candidates during + // direct-initialization. + // + // Note: SecondStepOfCopyInit is only ever true in this case when + // evaluating whether to produce a C++98 compatibility warning. + if (S.getLangOpts().CPlusPlus1z && Args.size() == 1 && + !SecondStepOfCopyInit) { + Expr *Initializer = Args[0]; + auto *SourceRD = Initializer->getType()->getAsCXXRecordDecl(); + if (SourceRD && S.isCompleteType(DeclLoc, Initializer->getType())) { + const auto &Conversions = SourceRD->getVisibleConversionFunctions(); + for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast(D->getDeclContext()); + D = D->getUnderlyingDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast(ConvTemplate->getTemplatedDecl()); + else + Conv = cast(D); + + if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) { + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), + ActingDC, Initializer, DestType, + CandidateSet, AllowExplicit, + /*AllowResultConversion*/false); + else + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, + DestType, CandidateSet, AllowExplicit, + /*AllowResultConversion*/false); + } + } + } + } + // Perform overload resolution and return the result. return CandidateSet.BestViableFunction(S, DeclLoc, Best); } @@ -3686,7 +3731,7 @@ static void TryConstructorInitialization(Sema &S, // the first phase is omitted. if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor())) Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, - CandidateSet, Ctors, Best, + CandidateSet, DestType, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructor=*/true, IsListInit); @@ -3700,7 +3745,7 @@ static void TryConstructorInitialization(Sema &S, if (Result == OR_No_Viable_Function) { AsInitializerList = false; Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs, - CandidateSet, Ctors, Best, + CandidateSet, DestType, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructors=*/false, IsListInit); @@ -3713,6 +3758,24 @@ static void TryConstructorInitialization(Sema &S, return; } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + + // In C++17, ResolveConstructorOverload can select a conversion function + // instead of a constructor. + if (auto *CD = dyn_cast(Best->Function)) { + // Add the user-defined conversion step that calls the conversion function. + QualType ConvType = CD->getConversionType(); + assert(S.Context.hasSameUnqualifiedType(ConvType, DestType) && + "should not have selected this conversion function"); + Sequence.AddUserConversionStep(CD, Best->FoundDecl, ConvType, + HadMultipleCandidates); + if (!S.Context.hasSameType(ConvType, DestType)) + Sequence.AddQualificationConversionStep(DestType, VK_RValue); + if (IsListInit) + Sequence.RewrapReferenceInitList(Entity.getType(), ILE); + return; + } + // C++11 [dcl.init]p6: // If a program calls for the default initialization of an object // of a const-qualified type T, T shall be a class type with a @@ -3741,7 +3804,6 @@ static void TryConstructorInitialization(Sema &S, // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. - bool HadMultipleCandidates = (CandidateSet.size() > 1); Sequence.AddConstructorInitializationStep( Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates, IsListInit | IsInitListCopy, AsInitializerList); @@ -4087,7 +4149,7 @@ static OverloadingResult TryRefInitWithConversionFunction( // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); - CandidateSet.clear(); + CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. @@ -4173,7 +4235,7 @@ static OverloadingResult TryRefInitWithConversionFunction( // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result - = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) + = CandidateSet.BestViableFunction(S, DeclLoc, Best)) return Result; FunctionDecl *Function = Best->Function; @@ -4687,7 +4749,7 @@ static void TryUserDefinedConversion(Sema &S, // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); - CandidateSet.clear(); + CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); // Determine whether we are allowed to call explicit constructors or // explicit conversion operators. @@ -4766,7 +4828,7 @@ static void TryUserDefinedConversion(Sema &S, // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result - = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { + = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { Sequence.SetOverloadFailure( InitializationSequence::FK_UserConversionOverloadFailed, Result); @@ -5657,7 +5719,7 @@ static ExprResult CopyObject(Sema &S, OverloadCandidateSet::iterator Best; switch (ResolveConstructorOverload( - S, Loc, CurInitExpr, CandidateSet, Ctors, Best, + S, Loc, CurInitExpr, CandidateSet, T, Ctors, Best, /*CopyInitializing=*/false, /*AllowExplicit=*/true, /*OnlyListConstructors=*/false, /*IsListInit=*/false, /*SecondStepOfCopyInit=*/true)) { @@ -5797,7 +5859,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, // Perform overload resolution. OverloadCandidateSet::iterator Best; OverloadingResult OR = ResolveConstructorOverload( - S, Loc, CurInitExpr, CandidateSet, Ctors, Best, + S, Loc, CurInitExpr, CandidateSet, CurInitExpr->getType(), Ctors, Best, /*CopyInitializing=*/false, /*AllowExplicit=*/true, /*OnlyListConstructors=*/false, /*IsListInit=*/false, /*SecondStepOfCopyInit=*/true); @@ -7535,8 +7597,7 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getSourceRange(); OverloadCandidateSet::iterator Best; OverloadingResult Ovl - = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best, - true); + = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); if (Ovl == OR_Deleted) { S.NoteDeletedFunction(Best->Function); } else { @@ -8415,7 +8476,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( OverloadCandidateSet::iterator Best; auto tryToResolveOverload = [&](bool OnlyListConstructors) -> OverloadingResult { - Candidates.clear(); + Candidates.clear(OverloadCandidateSet::CSK_Normal); for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) { NamedDecl *D = (*I)->getUnderlyingDecl(); if (D->isInvalidDecl()) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 8f28ec2fb8..66f0fad138 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -837,12 +837,13 @@ void OverloadCandidateSet::destroyCandidates() { } } -void OverloadCandidateSet::clear() { +void OverloadCandidateSet::clear(CandidateSetKind CSK) { destroyCandidates(); SlabAllocator.Reset(); NumInlineBytesUsed = 0; Candidates.clear(); Functions.clear(); + Kind = CSK; } namespace { @@ -3175,6 +3176,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence &User, OverloadCandidateSet &CandidateSet, bool AllowExplicit) { + CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); for (auto *D : S.LookupConstructors(To)) { auto Info = getConstructorInfo(D); if (!Info) @@ -3203,7 +3205,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, OverloadCandidateSet::iterator Best; switch (auto Result = CandidateSet.BestViableFunction(S, From->getLocStart(), - Best, true)) { + Best)) { case OR_Deleted: case OR_Success: { // Record the standard conversion we used and the conversion function. @@ -3250,6 +3252,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, bool AllowExplicit, bool AllowObjCConversionOnExplicit) { assert(AllowExplicit || !AllowObjCConversionOnExplicit); + CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); // Whether we will only visit constructors. bool ConstructorsOnly = false; @@ -3285,7 +3288,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, if (Result != OR_No_Viable_Function) return Result; // Never mind. - CandidateSet.clear(); + CandidateSet.clear( + OverloadCandidateSet::CSK_InitByUserDefinedConversion); // If we're list-initializing, we pass the individual elements as // arguments, not the entire list. @@ -3375,7 +3379,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, OverloadCandidateSet::iterator Best; switch (auto Result = CandidateSet.BestViableFunction(S, From->getLocStart(), - Best, true)) { + Best)) { case OR_Success: case OR_Deleted: // Record the standard conversion we used and the conversion function. @@ -4309,7 +4313,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, CXXRecordDecl *T2RecordDecl = dyn_cast(T2->getAs()->getDecl()); - OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal); + OverloadCandidateSet CandidateSet( + DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion); const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions(); for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { NamedDecl *D = *I; @@ -4379,7 +4384,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, bool HadMultipleCandidates = (CandidateSet.size() > 1); OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { + switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) { case OR_Success: // C++ [over.ics.ref]p1: // @@ -6788,7 +6793,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet, - bool AllowObjCConversionOnExplicit) { + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion) { assert(!Conversion->getDescribedFunctionTemplate() && "Conversion function templates use AddTemplateConversionCandidate"); QualType ConvType = Conversion->getConversionType().getNonReferenceType(); @@ -6803,6 +6809,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, ConvType = Conversion->getConversionType().getNonReferenceType(); } + // If we don't allow any conversion of the result type, ignore conversion + // functions that don't convert to exactly (possibly cv-qualified) T. + if (!AllowResultConversion && + !Context.hasSameUnqualifiedType(Conversion->getConversionType(), ToType)) + return; + // Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion // operator is only a candidate if its return type is the target type or // can be converted to the target type with a qualification conversion. @@ -6956,7 +6968,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, CXXRecordDecl *ActingDC, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, - bool AllowObjCConversionOnExplicit) { + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion) { assert(isa(FunctionTemplate->getTemplatedDecl()) && "Only conversion function templates permitted here"); @@ -6985,7 +6998,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType, - CandidateSet, AllowObjCConversionOnExplicit); + CandidateSet, AllowObjCConversionOnExplicit, + AllowResultConversion); } /// AddSurrogateCandidate - Adds a "surrogate" candidate function that @@ -8844,10 +8858,9 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1, /// isBetterOverloadCandidate - Determines whether the first overload /// candidate is a better candidate than the second (C++ 13.3.3p1). -bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, - const OverloadCandidate &Cand2, - SourceLocation Loc, - bool UserDefinedConversion) { +bool clang::isBetterOverloadCandidate( + Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2, + SourceLocation Loc, OverloadCandidateSet::CandidateSetKind Kind) { // Define viable functions to be better candidates than non-viable // functions. if (!Cand2.Viable) @@ -8929,7 +8942,8 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, // the type of the entity being initialized) is a better // conversion sequence than the standard conversion sequence // from the return type of F2 to the destination type. - if (UserDefinedConversion && Cand1.Function && Cand2.Function && + if (Kind == OverloadCandidateSet::CSK_InitByUserDefinedConversion && + Cand1.Function && Cand2.Function && isa(Cand1.Function) && isa(Cand2.Function)) { // First check whether we prefer one of the conversion functions over the @@ -9001,6 +9015,18 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, // Inherited from sibling base classes: still ambiguous. } + // FIXME: Work around a defect in the C++17 guaranteed copy elision wording, + // as combined with the resolution to CWG issue 243. + // + // When the context is initialization by constructor ([over.match.ctor] or + // either phase of [over.match.list]), a constructor is preferred over + // a conversion function. + if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 && + Cand1.Function && Cand2.Function && + isa(Cand1.Function) != + isa(Cand2.Function)) + return isa(Cand1.Function); + // Check for enable_if value-based overload resolution. if (Cand1.Function && Cand2.Function) { Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function); @@ -9100,8 +9126,7 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations( /// \returns The result of overload resolution. OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, - iterator &Best, - bool UserDefinedConversion) { + iterator &Best) { llvm::SmallVector Candidates; std::transform(begin(), end(), std::back_inserter(Candidates), [](OverloadCandidate &Cand) { return &Cand; }); @@ -9135,8 +9160,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, Best = end(); for (auto *Cand : Candidates) if (Cand->Viable) - if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, - UserDefinedConversion)) + if (Best == end() || + isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind)) Best = Cand; // If we didn't find any viable functions, abort. @@ -9148,10 +9173,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // Make sure that this function is better than every other viable // function. If not, we have an ambiguity. for (auto *Cand : Candidates) { - if (Cand->Viable && - Cand != Best && - !isBetterOverloadCandidate(S, *Best, *Cand, Loc, - UserDefinedConversion)) { + if (Cand->Viable && Cand != Best && + !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) { if (S.isEquivalentInternalLinkageDeclaration(Best->Function, Cand->Function)) { EquivalentCands.push_back(Cand->Function); @@ -10243,9 +10266,12 @@ struct CompareOverloadCandidatesForDisplay { Sema &S; SourceLocation Loc; size_t NumArgs; + OverloadCandidateSet::CandidateSetKind CSK; - CompareOverloadCandidatesForDisplay(Sema &S, SourceLocation Loc, size_t nArgs) - : S(S), NumArgs(nArgs) {} + CompareOverloadCandidatesForDisplay( + Sema &S, SourceLocation Loc, size_t NArgs, + OverloadCandidateSet::CandidateSetKind CSK) + : S(S), NumArgs(NArgs) {} bool operator()(const OverloadCandidate *L, const OverloadCandidate *R) { @@ -10259,8 +10285,10 @@ struct CompareOverloadCandidatesForDisplay { // TODO: introduce a tri-valued comparison for overload // candidates. Would be more worthwhile if we had a sort // that could exploit it. - if (isBetterOverloadCandidate(S, *L, *R, SourceLocation())) return true; - if (isBetterOverloadCandidate(S, *R, *L, SourceLocation())) return false; + if (isBetterOverloadCandidate(S, *L, *R, SourceLocation(), CSK)) + return true; + if (isBetterOverloadCandidate(S, *R, *L, SourceLocation(), CSK)) + return false; } else if (R->Viable) return false; @@ -10468,7 +10496,7 @@ void OverloadCandidateSet::NoteCandidates( } std::sort(Cands.begin(), Cands.end(), - CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size())); + CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind)); bool ReportedAmbiguousConversions = false; @@ -12917,7 +12945,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(), - Best)) { + Best)) { case OR_Success: // Overload resolution succeeded; we'll build the appropriate call // below. @@ -13311,7 +13339,7 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc, Expr *Range, ExprResult *CallExpr) { Scope *S = nullptr; - CandidateSet->clear(); + CandidateSet->clear(OverloadCandidateSet::CSK_Normal); if (!MemberLookup.empty()) { ExprResult MemberRef = BuildMemberReferenceExpr(Range, Range->getType(), Loc, diff --git a/test/SemaCXX/cxx1z-copy-omission.cpp b/test/SemaCXX/cxx1z-copy-omission.cpp index e2b8fd7961..cba6bc3be3 100644 --- a/test/SemaCXX/cxx1z-copy-omission.cpp +++ b/test/SemaCXX/cxx1z-copy-omission.cpp @@ -2,11 +2,11 @@ struct Noncopyable { Noncopyable(); - Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}} + Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}} expected-note 1+ {{not viable}} virtual ~Noncopyable(); }; struct Derived : Noncopyable {}; -struct NoncopyableAggr { +struct NoncopyableAggr { // expected-note 3{{candidate}} Noncopyable nc; }; struct Indestructible { @@ -38,11 +38,39 @@ Noncopyable nrvo() { Noncopyable nc1 = make(); Noncopyable nc2 = Noncopyable(); Noncopyable nc3 = Derived(); // expected-error {{deleted constructor}} +Noncopyable nc4((Noncopyable())); +Noncopyable nc5 = {Noncopyable()}; +Noncopyable nc6{Noncopyable()}; NoncopyableAggr nca1 = NoncopyableAggr{}; NoncopyableAggr nca2 = NoncopyableAggr{{}}; NoncopyableAggr nca3 = NoncopyableAggr{NoncopyableAggr{Noncopyable()}}; +template struct Convert { operator T(); }; // expected-note 1+{{candidate}} +Noncopyable conv1 = Convert(); +Noncopyable conv2((Convert())); +Noncopyable conv3 = {Convert()}; +Noncopyable conv4{Convert()}; + +Noncopyable ref_conv1 = Convert(); // expected-error {{deleted constructor}} +Noncopyable ref_conv2((Convert())); // expected-error {{deleted constructor}} +Noncopyable ref_conv3 = {Convert()}; // expected-error {{deleted constructor}} +Noncopyable ref_conv4{Convert()}; // expected-error {{deleted constructor}} + +Noncopyable derived_conv1 = Convert(); // expected-error {{deleted constructor}} +Noncopyable derived_conv2((Convert())); // expected-error {{deleted constructor}} +Noncopyable derived_conv3 = {Convert()}; // expected-error {{deleted constructor}} +Noncopyable derived_conv4{Convert()}; // expected-error {{deleted constructor}} + +NoncopyableAggr nc_aggr1 = Convert(); +NoncopyableAggr nc_aggr2((Convert())); +NoncopyableAggr nc_aggr3 = {Convert()}; // expected-error {{no viable conversion}} +NoncopyableAggr nc_aggr4{Convert()}; // expected-error {{no viable conversion}} +NoncopyableAggr nc_aggr5 = Convert(); // expected-error {{no viable}} +NoncopyableAggr nc_aggr6((Convert())); // expected-error {{no matching constructor}} +NoncopyableAggr nc_aggr7 = {Convert()}; +NoncopyableAggr nc_aggr8{Convert()}; + void test_expressions(bool b) { auto lambda = [a = make()] {}; -- 2.49.0