diff options
Diffstat (limited to 'clang/lib/Sema/SemaInit.cpp')
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 87 |
1 files changed, 74 insertions, 13 deletions
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 8aa60bcef07..59ec9e28516 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/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<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(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<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(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()) |