diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4061,6 +4061,12 @@ "; take the address of the argument with &|" "; remove *|" "; remove &}7">; +def note_ovl_candidate_bad_user_defined_conv : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "converting " + "%diff{from $ to $|from argument type to parameter type}3,4 " + "applies more than one implicit user-defined conversion" + >; def note_ovl_candidate_bad_arc_conv : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " "cannot implicitly convert argument " diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -463,6 +463,7 @@ struct BadConversionSequence { enum FailureKind { no_conversion, + suppressed_user_conversion, unrelated_class, bad_qualifiers, lvalue_ref_to_rvalue, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2944,10 +2944,20 @@ /// Allow both explicit conversion functions and explicit constructors. All }; + enum UserDefinedConversionsKind { + /// Allow user-defined conversions. + UDC_Allow, + + /// Find user-defined conversions but mark as invalid. + UDC_Suppress, + + /// Don't attempt to find user-defined conversions. + UDC_Skip, + }; ImplicitConversionSequence TryImplicitConversion(Expr *From, QualType ToType, - bool SuppressUserConversions, + UserDefinedConversionsKind UserConversions, AllowedExplicit AllowExplicit, bool InOverloadResolution, bool CStyle, @@ -3148,7 +3158,8 @@ void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef Args, OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions = false, + UserDefinedConversionsKind UserConversions + = UDC_Allow, bool PartialOverloading = false, bool AllowExplicit = true, bool AllowExplicitConversion = false, @@ -3159,7 +3170,7 @@ ArrayRef Args, OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, - bool SuppressUserConversions = false, + UserDefinedConversionsKind UserConversions = UDC_Allow, bool PartialOverloading = false, bool FirstArgumentIsBase = false); void AddMethodCandidate(DeclAccessPair FoundDecl, @@ -3167,7 +3178,8 @@ Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversion = false, + UserDefinedConversionsKind UserConversion + = UDC_Allow, OverloadCandidateParamOrder PO = {}); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, @@ -3175,7 +3187,8 @@ Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, + UserDefinedConversionsKind UserConversion + = UDC_Allow, bool PartialOverloading = false, ConversionSequenceList EarlyConversions = None, OverloadCandidateParamOrder PO = {}); @@ -3187,20 +3200,23 @@ Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, + UserDefinedConversionsKind UserConversions + = UDC_Allow, bool PartialOverloading = false, OverloadCandidateParamOrder PO = {}); void AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, - OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, + OverloadCandidateSet &CandidateSet, + UserDefinedConversionsKind UserConversions = UDC_Allow, bool PartialOverloading = false, bool AllowExplicit = true, ADLCallKind IsADLCandidate = ADLCallKind::NotADL, OverloadCandidateParamOrder PO = {}); bool CheckNonDependentConversions( FunctionTemplateDecl *FunctionTemplate, ArrayRef ParamTypes, ArrayRef Args, OverloadCandidateSet &CandidateSet, - ConversionSequenceList &Conversions, bool SuppressUserConversions, + ConversionSequenceList &Conversions, + UserDefinedConversionsKind UserConversions, CXXRecordDecl *ActingContext = nullptr, QualType ObjectType = QualType(), Expr::Classification ObjectClassification = {}, OverloadCandidateParamOrder PO = {}); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5181,7 +5181,7 @@ Decls.append(UME->decls_begin(), UME->decls_end()); const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase(); AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs, - /*SuppressUserConversions=*/false, + UDC_Allow, /*PartialOverloading=*/true, FirstArgumentIsBase); } else { FunctionDecl *FD = nullptr; @@ -5196,7 +5196,7 @@ else AddOverloadCandidate(FD, DeclAccessPair::make(FD, FD->getAccess()), Args, CandidateSet, - /*SuppressUserConversions=*/false, + UDC_Allow, /*PartialOverloading=*/true); } else if (auto DC = NakedFn->getType()->getAsCXXRecordDecl()) { @@ -5212,8 +5212,7 @@ SmallVector ArgExprs(1, NakedFn); ArgExprs.append(Args.begin(), Args.end()); AddFunctionCandidates(R.asUnresolvedSet(), ArgExprs, CandidateSet, - /*ExplicitArgs=*/nullptr, - /*SuppressUserConversions=*/false, + /*ExplicitArgs=*/nullptr, UDC_Allow, /*PartialOverloading=*/true); } } else { @@ -5260,15 +5259,14 @@ for (NamedDecl *C : LookupConstructors(RD)) { if (auto *FD = dyn_cast(C)) { AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args, - CandidateSet, - /*SuppressUserConversions=*/false, + CandidateSet, UDC_Allow, /*PartialOverloading=*/true, /*AllowExplicit*/ true); } else if (auto *FTD = dyn_cast(C)) { AddTemplateOverloadCandidate( FTD, DeclAccessPair::make(FTD, C->getAccess()), - /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet, - /*SuppressUserConversions=*/false, + /*ExplicitTemplateArgs=*/nullptr, Args, + CandidateSet, UDC_Allow, /*PartialOverloading=*/true); } } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -8700,7 +8700,7 @@ } else { ImplicitConversionSequence ICS = TryImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, AllowedExplicit::None, /*InOverloadResolution=*/false, /*CStyle=*/false, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2235,14 +2235,13 @@ if (FunctionTemplateDecl *FnTemplate = dyn_cast(D)) { S.AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, - Candidates, - /*SuppressUserConversions=*/false); + Candidates, Sema::UDC_Allow); continue; } FunctionDecl *Fn = cast(D); S.AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates, - /*SuppressUserConversions=*/false); + Sema::UDC_Allow); } // Do the resolution. @@ -3468,14 +3467,13 @@ if (FunctionTemplateDecl *FnTemplate = dyn_cast(D)) { S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, - Candidates, - /*SuppressUserConversions=*/false); + Candidates, Sema::UDC_Allow); continue; } FunctionDecl *Fn = cast(D); - S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, Candidates, - /*SuppressUserConversions=*/false); + S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, + Candidates, Sema::UDC_Allow); } SourceRange Range = TheCall->getSourceRange(); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3891,15 +3891,17 @@ // the first parameter of a constructor of class X, and the conversion // is to X or reference to (possibly cv-qualified X), // user-defined conversion sequences are not considered. - bool SuppressUserConversions = + Sema::UserDefinedConversionsKind UserConversions = SecondStepOfCopyInit || (IsListInit && Args.size() == 1 && isa(Args[0]) && - hasCopyOrMoveCtorParam(S.Context, Info)); + hasCopyOrMoveCtorParam(S.Context, Info)) + ? Sema::UDC_Suppress + : Sema::UDC_Allow; if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate( Info.ConstructorTmpl, Info.FoundDecl, - /*ExplicitArgs*/ nullptr, Args, CandidateSet, SuppressUserConversions, + /*ExplicitArgs*/ nullptr, Args, CandidateSet, UserConversions, /*PartialOverloading=*/false, AllowExplicit); else { // C++ [over.match.copy]p1: @@ -3913,7 +3915,7 @@ Args.size() == 1 && hasCopyOrMoveCtorParam(S.Context, Info); S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args, - CandidateSet, SuppressUserConversions, + CandidateSet, UserConversions, /*PartialOverloading=*/false, AllowExplicit, AllowExplicitConv); } @@ -4495,12 +4497,12 @@ S.AddTemplateOverloadCandidate( Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, Initializer, CandidateSet, - /*SuppressUserConversions=*/true, + Sema::UDC_Suppress, /*PartialOverloading*/ false, AllowExplicitCtors); else S.AddOverloadCandidate( Info.Constructor, Info.FoundDecl, Initializer, CandidateSet, - /*SuppressUserConversions=*/true, + Sema::UDC_Suppress, /*PartialOverloading*/ false, AllowExplicitCtors); } } @@ -4923,7 +4925,7 @@ // copy-initialization? ImplicitConversionSequence ICS = S.TryImplicitConversion(Initializer, TempEntity.getType(), - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, Sema::AllowedExplicit::None, /*FIXME:InOverloadResolution=*/false, /*CStyle=*/Kind.isCStyleOrFunctionalCast(), @@ -5152,12 +5154,12 @@ S.AddTemplateOverloadCandidate( Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, Initializer, CandidateSet, - /*SuppressUserConversions=*/true, + Sema::UDC_Suppress, /*PartialOverloading*/ false, AllowExplicit); else S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Initializer, CandidateSet, - /*SuppressUserConversions=*/true, + Sema::UDC_Suppress, /*PartialOverloading*/ false, AllowExplicit); } } @@ -5862,7 +5864,7 @@ ImplicitConversionSequence ICS = S.TryImplicitConversion(Initializer, DestType, - /*SuppressUserConversions*/true, + Sema::UDC_Suppress, Sema::AllowedExplicit::None, /*InOverloadResolution*/ false, /*CStyle=*/Kind.isCStyleOrFunctionalCast(), @@ -9805,16 +9807,17 @@ // FIXME: The "second phase of [over.match.list] case can also // theoretically happen here, but it's not clear whether we can // ever have a parameter of the right type. - bool SuppressUserConversions = Kind.isCopyInit(); + UserDefinedConversionsKind UserConversions + = Kind.isCopyInit() ? Sema::UDC_Suppress : Sema::UDC_Allow; if (TD) AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr, - Inits, Candidates, SuppressUserConversions, + Inits, Candidates, UserConversions, /*PartialOverloading*/ false, AllowExplicit); else AddOverloadCandidate(GD, I.getPair(), Inits, Candidates, - SuppressUserConversions, + UserConversions, /*PartialOverloading*/ false, AllowExplicit); } return Candidates.BestViableFunction(*this, Kind.getLocation(), Best); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3247,27 +3247,29 @@ if (CXXMethodDecl *M = dyn_cast(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodCandidate(M, Cand, RD, ThisTy, Classification, - llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + llvm::makeArrayRef(&Arg, NumArgs), OCS, + Sema::UDC_Suppress); else if (CtorInfo) AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl, llvm::makeArrayRef(&Arg, NumArgs), OCS, - /*SuppressUserConversions*/ true); + Sema::UDC_Suppress); else AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS, - /*SuppressUserConversions*/ true); + Sema::UDC_Suppress); } else if (FunctionTemplateDecl *Tmpl = dyn_cast(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodTemplateCandidate( Tmpl, Cand, RD, nullptr, ThisTy, Classification, - llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + llvm::makeArrayRef(&Arg, NumArgs), OCS, Sema::UDC_Suppress); else if (CtorInfo) AddTemplateOverloadCandidate( CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr, - llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + llvm::makeArrayRef(&Arg, NumArgs), OCS, Sema::UDC_Suppress); else AddTemplateOverloadCandidate( - Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, + Sema::UDC_Suppress); } else { assert(isa(Cand.getDecl()) && "illegal Kind of operator = Decl"); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5427,7 +5427,7 @@ } ImplicitConversionSequence ICS = TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(), - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, AllowedExplicit::None, /*InOverloadResolution=*/false, /*CStyle=*/false, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -93,6 +93,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence& User, OverloadCandidateSet& Conversions, + Sema::UserDefinedConversionsKind UserConversions, AllowedExplicit AllowExplicit, bool AllowObjCConversionOnExplicit); @@ -1317,17 +1318,15 @@ /// is not an option. See TryImplicitConversion for more information. static ImplicitConversionSequence TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType, - bool SuppressUserConversions, + Sema::UserDefinedConversionsKind UserConversions, AllowedExplicit AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion, bool AllowObjCConversionOnExplicit) { ImplicitConversionSequence ICS; - - if (SuppressUserConversions) { - // We're not in the case above, so there is no conversion that - // we can perform. + + if (UserConversions == Sema::UDC_Skip) { ICS.setBad(BadConversionSequence::no_conversion, From, ToType); return ICS; } @@ -1336,7 +1335,7 @@ OverloadCandidateSet Conversions(From->getExprLoc(), OverloadCandidateSet::CSK_Normal); switch (IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, - Conversions, AllowExplicit, + Conversions, UserConversions, AllowExplicit, AllowObjCConversionOnExplicit)) { case OR_Success: case OR_Deleted: @@ -1382,12 +1381,17 @@ ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function); break; - // Fall through. case OR_No_Viable_Function: ICS.setBad(BadConversionSequence::no_conversion, From, ToType); break; } + // If we found a viable conversion but user conversions are not allowed, + // throw it out and mark it as such. + if (UserConversions == Sema::UDC_Suppress && !ICS.isBad()) + ICS.setBad(BadConversionSequence::suppressed_user_conversion, + From, ToType); + return ICS; } @@ -1420,7 +1424,7 @@ /// be initialized with __strong id* or __weak id* arguments. static ImplicitConversionSequence TryImplicitConversion(Sema &S, Expr *From, QualType ToType, - bool SuppressUserConversions, + Sema::UserDefinedConversionsKind UserConversions, AllowedExplicit AllowExplicit, bool InOverloadResolution, bool CStyle, @@ -1467,7 +1471,7 @@ return ICS; } - return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions, + return TryUserDefinedConversion(S, From, ToType, UserConversions, AllowExplicit, InOverloadResolution, CStyle, AllowObjCWritebackConversion, AllowObjCConversionOnExplicit); @@ -1475,13 +1479,14 @@ ImplicitConversionSequence Sema::TryImplicitConversion(Expr *From, QualType ToType, - bool SuppressUserConversions, + UserDefinedConversionsKind UserConversions, AllowedExplicit AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion) { - return ::TryImplicitConversion(*this, From, ToType, SuppressUserConversions, - AllowExplicit, InOverloadResolution, CStyle, + return ::TryImplicitConversion(*this, From, ToType, + UserConversions, AllowExplicit, + InOverloadResolution, CStyle, AllowObjCWritebackConversion, /*AllowObjCConversionOnExplicit=*/false); } @@ -1513,7 +1518,7 @@ CheckObjCBridgeRelatedConversions(From->getBeginLoc(), ToType, From->getType(), From); ICS = ::TryImplicitConversion(*this, From, ToType, - /*SuppressUserConversions=*/false, + UDC_Allow, AllowExplicit ? AllowedExplicit::All : AllowedExplicit::None, /*InOverloadResolution=*/false, @@ -3334,17 +3339,20 @@ if (Usable) { // If the first argument is (a reference to) the target type, // suppress conversions. - bool SuppressUserConversions = isFirstArgumentCompatibleWithType( - S.Context, Info.Constructor, ToType); + Sema::UserDefinedConversionsKind UserConversions + = isFirstArgumentCompatibleWithType( + S.Context, Info.Constructor, ToType) + ? Sema::UDC_Suppress + : Sema::UDC_Allow; if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, From, - CandidateSet, SuppressUserConversions, + CandidateSet, UserConversions, /*PartialOverloading*/ false, AllowExplicit); else S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From, - CandidateSet, SuppressUserConversions, + CandidateSet, UserConversions, /*PartialOverloading*/ false, AllowExplicit); } } @@ -3379,6 +3387,22 @@ llvm_unreachable("Invalid OverloadResult!"); } +static Sema::UserDefinedConversionsKind +StrengthenUserConversionSuppression(bool Suppress, + Sema::UserDefinedConversionsKind K) { + if (!Suppress) + return Sema::UDC_Allow; + + switch (K) { + case Sema::UDC_Allow: + return Sema::UDC_Suppress; + + case Sema::UDC_Suppress: + case Sema::UDC_Skip: + return Sema::UDC_Skip; + } +} + /// Determines whether there is a user-defined conversion sequence /// (C++ [over.ics.user]) that converts expression From to the type /// ToType. If such a conversion exists, User will contain the @@ -3397,6 +3421,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence &User, OverloadCandidateSet &CandidateSet, + Sema::UserDefinedConversionsKind UserConversions, AllowedExplicit AllowExplicit, bool AllowObjCConversionOnExplicit) { assert(AllowExplicit != AllowedExplicit::None || @@ -3472,7 +3497,9 @@ S.AddTemplateOverloadCandidate( Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs), - CandidateSet, SuppressUserConversions, + CandidateSet, + StrengthenUserConversionSuppression( + SuppressUserConversions, UserConversions), /*PartialOverloading*/ false, AllowExplicit == AllowedExplicit::All); else @@ -3480,7 +3507,9 @@ // From->ToType conversion via an static cast (c-style, etc). S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, llvm::makeArrayRef(Args, NumArgs), - CandidateSet, SuppressUserConversions, + CandidateSet, + StrengthenUserConversionSuppression( + SuppressUserConversions, UserConversions), /*PartialOverloading*/ false, AllowExplicit == AllowedExplicit::All); } @@ -3606,7 +3635,7 @@ OverloadCandidateSet::CSK_Normal); OverloadingResult OvResult = IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined, - CandidateSet, AllowedExplicit::None, false); + CandidateSet, UDC_Allow, AllowedExplicit::None, false); if (!(OvResult == OR_Ambiguous || (OvResult == OR_No_Viable_Function && !CandidateSet.empty()))) @@ -4866,7 +4895,10 @@ // the argument expression. Any difference in top-level // cv-qualification is subsumed by the initialization itself // and does not constitute a conversion. - ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions, + ICS = TryImplicitConversion(S, Init, T1, + SuppressUserConversions + ? Sema::UDC_Suppress + : Sema::UDC_Allow, AllowedExplicit::None, /*InOverloadResolution=*/false, /*CStyle=*/false, @@ -4913,7 +4945,7 @@ static ImplicitConversionSequence TryCopyInitialization(Sema &S, Expr *From, QualType ToType, - bool SuppressUserConversions, + Sema::UserDefinedConversionsKind UserConversions, bool InOverloadResolution, bool AllowObjCWritebackConversion, bool AllowExplicit = false); @@ -4922,7 +4954,7 @@ /// initializer list From. static ImplicitConversionSequence TryListConversion(Sema &S, InitListExpr *From, QualType ToType, - bool SuppressUserConversions, + Sema::UserDefinedConversionsKind UserConversions, bool InOverloadResolution, bool AllowObjCWritebackConversion) { // C++11 [over.ics.list]p1: @@ -4953,7 +4985,7 @@ if (S.Context.hasSameUnqualifiedType(InitType, ToType) || S.IsDerivedFrom(From->getBeginLoc(), InitType, ToType)) return TryCopyInitialization(S, From->getInit(0), ToType, - SuppressUserConversions, + UserConversions, InOverloadResolution, AllowObjCWritebackConversion); } @@ -4998,7 +5030,7 @@ for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) { Expr *Init = From->getInit(i); ImplicitConversionSequence ICS = - TryCopyInitialization(S, Init, X, SuppressUserConversions, + TryCopyInitialization(S, Init, X, UserConversions, InOverloadResolution, AllowObjCWritebackConversion); // If a single element isn't convertible, fail. @@ -5035,7 +5067,7 @@ // implicit conversion sequence is a user-defined conversion sequence. if (ToType->isRecordType() && !ToType->isAggregateType()) { // This function can deal with initializer lists. - return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions, + return TryUserDefinedConversion(S, From, ToType, UserConversions, AllowedExplicit::None, InOverloadResolution, /*CStyle=*/false, AllowObjCWritebackConversion, @@ -5103,14 +5135,14 @@ if (RefRelationship >= Sema::Ref_Related) { return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(), - SuppressUserConversions, + UserConversions, /*AllowExplicit=*/false); } } // Otherwise, we bind the reference to a temporary created from the // initializer list. - Result = TryListConversion(S, From, T1, SuppressUserConversions, + Result = TryListConversion(S, From, T1, UserConversions, InOverloadResolution, AllowObjCWritebackConversion); if (Result.isFailure()) @@ -5145,7 +5177,7 @@ unsigned NumInits = From->getNumInits(); if (NumInits == 1 && !isa(From->getInit(0))) Result = TryCopyInitialization(S, From->getInit(0), ToType, - SuppressUserConversions, + UserConversions, InOverloadResolution, AllowObjCWritebackConversion); // - if the initializer list has no elements, the implicit conversion @@ -5173,21 +5205,21 @@ /// do not permit any user-defined conversion sequences. static ImplicitConversionSequence TryCopyInitialization(Sema &S, Expr *From, QualType ToType, - bool SuppressUserConversions, + Sema::UserDefinedConversionsKind UserConversions, bool InOverloadResolution, bool AllowObjCWritebackConversion, bool AllowExplicit) { if (InitListExpr *FromInitList = dyn_cast(From)) - return TryListConversion(S, FromInitList, ToType, SuppressUserConversions, + return TryListConversion(S, FromInitList, ToType, UserConversions, InOverloadResolution,AllowObjCWritebackConversion); if (ToType->isReferenceType()) return TryReferenceInit(S, From, ToType, /*FIXME:*/ From->getBeginLoc(), - SuppressUserConversions, AllowExplicit); + UserConversions, AllowExplicit); return TryImplicitConversion(S, From, ToType, - SuppressUserConversions, + UserConversions, AllowedExplicit::None, InOverloadResolution, /*CStyle=*/false, @@ -5202,7 +5234,7 @@ ExprValueKind FromVK) { OpaqueValueExpr TmpExpr(Loc, FromQTy, FromVK); ImplicitConversionSequence ICS = - TryCopyInitialization(S, &TmpExpr, ToQTy, true, true, false); + TryCopyInitialization(S, &TmpExpr, ToQTy, Sema::UDC_Suppress, true, false); return !ICS.isBad(); } @@ -5400,6 +5432,7 @@ case BadConversionSequence::no_conversion: case BadConversionSequence::unrelated_class: + case BadConversionSequence::suppressed_user_conversion: break; } @@ -5435,7 +5468,7 @@ static ImplicitConversionSequence TryContextuallyConvertToBool(Sema &S, Expr *From) { return TryImplicitConversion(S, From, S.Context.BoolTy, - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, AllowedExplicit::Conversions, /*InOverloadResolution=*/false, /*CStyle=*/false, @@ -5551,7 +5584,7 @@ CCE == Sema::CCEK_ConstexprIf || CCE == Sema::CCEK_ExplicitBool ? TryContextuallyConvertToBool(S, From) : TryCopyInitialization(S, From, T, - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, /*InOverloadResolution=*/false, /*AllowObjCWritebackConversion=*/false, /*AllowExplicit=*/false); @@ -5707,7 +5740,7 @@ ImplicitConversionSequence ICS = TryImplicitConversion(S, From, Ty, // FIXME: Are these flags correct? - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, AllowedExplicit::Conversions, /*InOverloadResolution=*/false, /*CStyle=*/false, @@ -6132,7 +6165,8 @@ /// code completion. void Sema::AddOverloadCandidate( FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef Args, - OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + OverloadCandidateSet &CandidateSet, + UserDefinedConversionsKind UserConversions, bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions, ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions, OverloadCandidateParamOrder PO) { @@ -6153,7 +6187,7 @@ // is irrelevant. AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Expr::Classification::makeSimpleLValue(), Args, - CandidateSet, SuppressUserConversions, + CandidateSet, UserConversions, PartialOverloading, EarlyConversions, PO); return; } @@ -6325,7 +6359,7 @@ // parameter of F. QualType ParamType = Proto->getParamType(ArgIdx); Candidate.Conversions[ConvIdx] = TryCopyInitialization( - *this, Args[ArgIdx], ParamType, SuppressUserConversions, + *this, Args[ArgIdx], ParamType, UserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount, AllowExplicitConversions); @@ -6398,7 +6432,7 @@ ImplicitConversionSequence ConversionState = TryCopyInitialization(*this, argExpr, param->getType(), - /*SuppressUserConversions*/false, + UDC_Allow, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount, @@ -6624,7 +6658,7 @@ ArrayRef Args, OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs, - bool SuppressUserConversions, + UserDefinedConversionsKind UserConversions, bool PartialOverloading, bool FirstArgumentIsBase) { for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { @@ -6656,13 +6690,13 @@ FunTmpl, F.getPair(), cast(FunTmpl->getDeclContext()), ExplicitTemplateArgs, ObjectType, ObjectClassification, - FunctionArgs, CandidateSet, SuppressUserConversions, + FunctionArgs, CandidateSet, UserConversions, PartialOverloading); } else { AddMethodCandidate(cast(FD), F.getPair(), cast(FD)->getParent(), ObjectType, ObjectClassification, FunctionArgs, CandidateSet, - SuppressUserConversions, PartialOverloading); + UserConversions, PartialOverloading); } } else { // This branch handles both standalone functions and static methods. @@ -6678,11 +6712,11 @@ if (FunTmpl) { AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs, - CandidateSet, SuppressUserConversions, + CandidateSet, UserConversions, PartialOverloading); } else { AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet, - SuppressUserConversions, PartialOverloading); + UserConversions, PartialOverloading); } } } @@ -6694,7 +6728,7 @@ Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions, + UserDefinedConversionsKind UserConversions, OverloadCandidateParamOrder PO) { NamedDecl *Decl = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast(Decl->getDeclContext()); @@ -6708,11 +6742,11 @@ AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, /*ExplicitArgs*/ nullptr, ObjectType, ObjectClassification, Args, CandidateSet, - SuppressUserConversions, false, PO); + UserConversions, false, PO); } else { AddMethodCandidate(cast(Decl), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, - SuppressUserConversions, false, None, PO); + UserConversions, false, None, PO); } } @@ -6729,7 +6763,7 @@ Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions, + UserDefinedConversionsKind UserConversions, bool PartialOverloading, ConversionSequenceList EarlyConversions, OverloadCandidateParamOrder PO) { @@ -6843,7 +6877,7 @@ QualType ParamType = Proto->getParamType(ArgIdx); Candidate.Conversions[ConvIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, - SuppressUserConversions, + UserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount); @@ -6882,7 +6916,8 @@ CXXRecordDecl *ActingContext, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, - OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + OverloadCandidateSet &CandidateSet, + UserDefinedConversionsKind UserConversions, bool PartialOverloading, OverloadCandidateParamOrder PO) { if (!CandidateSet.isNewCandidate(MethodTmpl, PO)) return; @@ -6904,7 +6939,7 @@ PartialOverloading, [&](ArrayRef ParamTypes) { return CheckNonDependentConversions( MethodTmpl, ParamTypes, Args, CandidateSet, Conversions, - SuppressUserConversions, ActingContext, ObjectType, + UserConversions, ActingContext, ObjectType, ObjectClassification, PO); })) { OverloadCandidate &Candidate = @@ -6936,7 +6971,7 @@ "Specialization is not a member function?"); AddMethodCandidate(cast(Specialization), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, - CandidateSet, SuppressUserConversions, PartialOverloading, + CandidateSet, UserConversions, PartialOverloading, Conversions, PO); } @@ -6952,7 +6987,8 @@ void Sema::AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, - OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + OverloadCandidateSet &CandidateSet, + UserDefinedConversionsKind UserConversions, bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO) { if (!CandidateSet.isNewCandidate(FunctionTemplate, PO)) @@ -6987,7 +7023,7 @@ PartialOverloading, [&](ArrayRef ParamTypes) { return CheckNonDependentConversions( FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions, - SuppressUserConversions, nullptr, QualType(), {}, PO); + UserConversions, nullptr, QualType(), {}, PO); })) { OverloadCandidate &Candidate = CandidateSet.addCandidate(Conversions.size(), Conversions); @@ -7018,7 +7054,7 @@ // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); AddOverloadCandidate( - Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, + Specialization, FoundDecl, Args, CandidateSet, UserConversions, PartialOverloading, AllowExplicit, /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions, PO); } @@ -7029,7 +7065,8 @@ bool Sema::CheckNonDependentConversions( FunctionTemplateDecl *FunctionTemplate, ArrayRef ParamTypes, ArrayRef Args, OverloadCandidateSet &CandidateSet, - ConversionSequenceList &Conversions, bool SuppressUserConversions, + ConversionSequenceList &Conversions, + UserDefinedConversionsKind UserConversions, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, OverloadCandidateParamOrder PO) { // FIXME: The cases in which we allow explicit conversions for constructor @@ -7071,7 +7108,7 @@ : (ThisConversions + I); Conversions[ConvIdx] = TryCopyInitialization(*this, Args[I], ParamType, - SuppressUserConversions, + UserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount, @@ -7271,7 +7308,7 @@ ImplicitConversionSequence ICS = TryCopyInitialization(*this, TheTemporaryCall, ToType, - /*SuppressUserConversions=*/true, + Sema::UDC_Suppress, /*InOverloadResolution=*/false, /*AllowObjCWritebackConversion=*/false); @@ -7304,6 +7341,9 @@ break; case ImplicitConversionSequence::BadConversion: + if (ICS.Bad.Kind == BadConversionSequence::suppressed_user_conversion) + Candidate.Conversions[0].setBad(BadConversionSequence::suppressed_user_conversion, + ICS.Bad.getFromType(), ICS.Bad.getToType()); Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_final_conversion; return; @@ -7466,7 +7506,7 @@ QualType ParamType = Proto->getParamType(ArgIdx); Candidate.Conversions[ArgIdx + 1] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, /*InOverloadResolution=*/false, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount); @@ -7518,7 +7558,7 @@ if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) AddTemplateOverloadCandidate( FunTmpl, F.getPair(), ExplicitTemplateArgs, - {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false, + {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, UDC_Allow, false, true, ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed); } else { if (ExplicitTemplateArgs) @@ -7527,7 +7567,7 @@ if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) AddOverloadCandidate(FD, F.getPair(), {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, - false, false, true, false, ADLCallKind::NotADL, + UDC_Allow, false, true, false, ADLCallKind::NotADL, None, OverloadCandidateParamOrder::Reversed); } } @@ -7580,7 +7620,7 @@ ++Oper) AddMethodCandidate(Oper.getPair(), Args[0]->getType(), Args[0]->Classify(Context), Args.slice(1), - CandidateSet, /*SuppressUserConversion=*/false, PO); + CandidateSet, Sema::UDC_Allow, PO); } } @@ -7633,7 +7673,9 @@ } else { Candidate.Conversions[ArgIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx], - ArgIdx == 0 && IsAssignmentOperator, + ArgIdx == 0 && IsAssignmentOperator + ? Sema::UDC_Suppress + : Sema::UDC_Allow, /*InOverloadResolution=*/false, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount); @@ -9278,14 +9320,15 @@ if (ExplicitTemplateArgs) continue; - AddOverloadCandidate( - FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false, - PartialOverloading, /*AllowExplicit=*/true, - /*AllowExplicitConversions=*/false, ADLCallKind::UsesADL); + AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet, + Sema::UDC_Allow, PartialOverloading, + /*AllowExplicit*/ true, + /*AllowExplicitConversions*/ false, + ADLCallKind::UsesADL); if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) { AddOverloadCandidate( FD, FoundDecl, {Args[1], Args[0]}, CandidateSet, - /*SuppressUserConversions=*/false, PartialOverloading, + UDC_Allow, PartialOverloading, /*AllowExplicit=*/true, /*AllowExplicitConversions=*/false, ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed); } @@ -9293,16 +9336,16 @@ auto *FTD = cast(*I); AddTemplateOverloadCandidate( FTD, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet, - /*SuppressUserConversions=*/false, PartialOverloading, + UDC_Allow, PartialOverloading, /*AllowExplicit=*/true, ADLCallKind::UsesADL); if (CandidateSet.getRewriteInfo().shouldAddReversed( Context, FTD->getTemplatedDecl())) { AddTemplateOverloadCandidate( FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]}, - CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, + CandidateSet, UDC_Allow, PartialOverloading, /*AllowExplicit=*/true, ADLCallKind::UsesADL, OverloadCandidateParamOrder::Reversed); - } + } } } } @@ -10362,6 +10405,14 @@ !checkAddressOfCandidateIsAvailable(S, Cand->Function)) return; + if (Conv.Bad.Kind == BadConversionSequence::suppressed_user_conversion) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_user_defined_conv) + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second + << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy; + return; + } + // Emit the generic diagnostic and, optionally, add the hints to it. PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv); FDiag << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc @@ -10938,8 +10989,6 @@ case ovl_fail_trivial_conversion: case ovl_fail_bad_final_conversion: case ovl_fail_final_conversion_not_exact: - return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind()); - case ovl_fail_bad_conversion: { unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); for (unsigned N = Cand->Conversions.size(); I != N; ++I) @@ -11338,7 +11387,9 @@ else { Cand->Conversions[ConvIdx] = TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ParamIdx], - SuppressUserConversions, + SuppressUserConversions + ? Sema::UDC_Suppress + : Sema::UDC_Allow, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ S.getLangOpts().ObjCAutoRefCount); @@ -12351,7 +12402,7 @@ return; S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet, - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, PartialOverloading); return; } @@ -12360,7 +12411,7 @@ = dyn_cast(Callee)) { S.AddTemplateOverloadCandidate(FuncTemplate, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet, - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, PartialOverloading); return; } @@ -13897,7 +13948,7 @@ if (getLangOpts().MicrosoftExt && isa(Func)) { AddOverloadCandidate(cast(Func), I.getPair(), Args, CandidateSet, - /*SuppressUserConversions*/ false); + Sema::UDC_Allow); } else if ((Method = dyn_cast(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. @@ -13906,12 +13957,12 @@ AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType, ObjectClassification, Args, CandidateSet, - /*SuppressUserConversions=*/false); + Sema::UDC_Allow); } else { AddMethodTemplateCandidate( cast(Func), I.getPair(), ActingDC, TemplateArgs, ObjectType, ObjectClassification, Args, CandidateSet, - /*SuppressUserConversions=*/false); + Sema::UDC_Allow); } } @@ -14107,7 +14158,7 @@ Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Object.get()->getType(), Object.get()->Classify(Context), Args, CandidateSet, - /*SuppressUserConversion=*/false); + Sema::UDC_Allow); } // C++ [over.call.object]p2: @@ -14379,7 +14430,7 @@ for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context), - None, CandidateSet, /*SuppressUserConversion=*/false); + None, CandidateSet, Sema::UDC_Allow); } bool HadMultipleCandidates = (CandidateSet.size() > 1); diff --git a/clang/test/CXX/drs/dr0xx.cpp b/clang/test/CXX/drs/dr0xx.cpp --- a/clang/test/CXX/drs/dr0xx.cpp +++ b/clang/test/CXX/drs/dr0xx.cpp @@ -964,7 +964,7 @@ struct C {}; struct B { B(B&); // expected-note 0-1{{candidate}} - B(C); // expected-note 0-1{{no known conversion from 'dr84::B' to 'dr84::C'}} + B(C); // expected-note 0-1{{'dr84::B' to 'dr84::C' applies more than one implicit user-defined conversion}} operator C() const; }; A a; diff --git a/clang/test/SemaCXX/user-defined-conversions.cpp b/clang/test/SemaCXX/user-defined-conversions.cpp --- a/clang/test/SemaCXX/user-defined-conversions.cpp +++ b/clang/test/SemaCXX/user-defined-conversions.cpp @@ -97,3 +97,31 @@ a = b; // expected-error{{calling a private constructor of class 'rdar10202900::A'}} } } + +namespace more_than_one { + struct X { + operator int(); + }; + + struct Y { + operator X(); // expected-note{{converting from 'more_than_one::X' to 'int' applies more than one implicit user-defined conversion}} + }; + + Y a; + int b = a; // expected-error{{no viable conversion}} + int c = X(a); + + struct X2 {}; + + struct Y2 { + Y2(X2); + }; + + struct Z { // expected-note 2{{candidate constructor (the implicit}} + Z(Y2); // expected-note{{converting from 'more_than_one::X2' to 'more_than_one::Y2' applies more than one implicit user-defined conversion}} + }; + + X2 x; + Z z = x; // expected-error{{no viable conversion}} + Z z2 = Y2(x); +}