Author: rsmith Date: Tue Sep 26 11:37:55 2017 New Revision: 314231 URL: http://llvm.org/viewvc/llvm-project?rev=314231&view=rev Log: 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. Modified: cfe/trunk/include/clang/Sema/Overload.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaCodeComplete.cpp cfe/trunk/lib/Sema/SemaInit.cpp cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp Modified: cfe/trunk/include/clang/Sema/Overload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=314231&r1=314230&r2=314231&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Overload.h (original) +++ cfe/trunk/include/clang/Sema/Overload.h Tue Sep 26 11:37:55 2017 @@ -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<OverloadCandidate>::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; Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=314231&r1=314230&r2=314231&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Sep 26 11:37:55 2017 @@ -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, Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=314231&r1=314230&r2=314231&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original) +++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Tue Sep 26 11:37:55 2017 @@ -4293,7 +4293,8 @@ static void mergeCandidatesWithResults(S 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. Modified: cfe/trunk/lib/Sema/SemaInit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=314231&r1=314230&r2=314231&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp (original) +++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Sep 26 11:37:55 2017 @@ -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, Sour } } + // 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<CXXRecordDecl>(D->getDeclContext()); + D = D->getUnderlyingDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(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 // 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 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 return; } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + + // In C++17, ResolveConstructorOverload can select a conversion function + // instead of a constructor. + if (auto *CD = dyn_cast<CXXConversionDecl>(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 // 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 TryRefInitWithC // 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 TryRefInitWithC // 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(Sem // 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(Sem // 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 CheckCXX98CompatAccessibleCo // 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(Se << 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::DeduceTemplateSpecializat 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()) Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=314231&r1=314230&r2=314231&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Sep 26 11:37:55 2017 @@ -837,12 +837,13 @@ void OverloadCandidateSet::destroyCandid } } -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(S 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(S 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 *F 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 *F 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 *F 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, Implic CXXRecordDecl *T2RecordDecl = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->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, Implic 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(CXXConversi 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(CXXConversi 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(Fun CXXRecordDecl *ActingDC, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, - bool AllowObjCConversionOnExplicit) { + bool AllowObjCConversionOnExplicit, + bool AllowResultConversion) { assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) && "Only conversion function templates permitted here"); @@ -6985,7 +6998,8 @@ Sema::AddTemplateConversionCandidate(Fun // 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(c /// 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(Se // 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<CXXConversionDecl>(Cand1.Function) && isa<CXXConversionDecl>(Cand2.Function)) { // First check whether we prefer one of the conversion functions over the @@ -9001,6 +9015,18 @@ bool clang::isBetterOverloadCandidate(Se // 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<CXXConstructorDecl>(Cand1.Function) != + isa<CXXConstructorDecl>(Cand2.Function)) + return isa<CXXConstructorDecl>(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::diagnoseEquivalentInternalLin /// \returns The result of overload resolution. OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, - iterator &Best, - bool UserDefinedConversion) { + iterator &Best) { llvm::SmallVector<OverloadCandidate *, 16> Candidates; std::transform(begin(), end(), std::back_inserter(Candidates), [](OverloadCandidate &Cand) { return &Cand; }); @@ -9135,8 +9160,8 @@ OverloadCandidateSet::BestViableFunction 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 // 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 CompareOverloadCandidatesForDispl 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 CompareOverloadCandidatesForDispl // 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::NoteCandidate } 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 // 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(SourceLo Expr *Range, ExprResult *CallExpr) { Scope *S = nullptr; - CandidateSet->clear(); + CandidateSet->clear(OverloadCandidateSet::CSK_Normal); if (!MemberLookup.empty()) { ExprResult MemberRef = BuildMemberReferenceExpr(Range, Range->getType(), Loc, Modified: cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp?rev=314231&r1=314230&r2=314231&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp Tue Sep 26 11:37:55 2017 @@ -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<typename T> struct Convert { operator T(); }; // expected-note 1+{{candidate}} +Noncopyable conv1 = Convert<Noncopyable>(); +Noncopyable conv2((Convert<Noncopyable>())); +Noncopyable conv3 = {Convert<Noncopyable>()}; +Noncopyable conv4{Convert<Noncopyable>()}; + +Noncopyable ref_conv1 = Convert<Noncopyable&>(); // expected-error {{deleted constructor}} +Noncopyable ref_conv2((Convert<Noncopyable&>())); // expected-error {{deleted constructor}} +Noncopyable ref_conv3 = {Convert<Noncopyable&>()}; // expected-error {{deleted constructor}} +Noncopyable ref_conv4{Convert<Noncopyable&>()}; // expected-error {{deleted constructor}} + +Noncopyable derived_conv1 = Convert<Derived>(); // expected-error {{deleted constructor}} +Noncopyable derived_conv2((Convert<Derived>())); // expected-error {{deleted constructor}} +Noncopyable derived_conv3 = {Convert<Derived>()}; // expected-error {{deleted constructor}} +Noncopyable derived_conv4{Convert<Derived>()}; // expected-error {{deleted constructor}} + +NoncopyableAggr nc_aggr1 = Convert<NoncopyableAggr>(); +NoncopyableAggr nc_aggr2((Convert<NoncopyableAggr>())); +NoncopyableAggr nc_aggr3 = {Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}} +NoncopyableAggr nc_aggr4{Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}} +NoncopyableAggr nc_aggr5 = Convert<Noncopyable>(); // expected-error {{no viable}} +NoncopyableAggr nc_aggr6((Convert<Noncopyable>())); // expected-error {{no matching constructor}} +NoncopyableAggr nc_aggr7 = {Convert<Noncopyable>()}; +NoncopyableAggr nc_aggr8{Convert<Noncopyable>()}; + void test_expressions(bool b) { auto lambda = [a = make()] {}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits