logan-5 created this revision. logan-5 added a reviewer: rsmith. logan-5 added a project: clang. Herald added a subscriber: cfe-commits.
The current text of the 'note' diagnostic for bad conversions is confusing in the presence of user-defined conversion operations: https://godbolt.org/z/zrgeHH For the first error, the conversion function is simply pointed at in a note without any further explanation. For the second error, the final note claims there is no conversion from X2 to Y2, even though it is plainly visible in the source code. The reason for the error is that only one implicit user-defined conversion may be applied in these circumstances, but the error message is misleading to those who may not know this rule. This patch clarifies this situation with a better diagnostic message. It does so by finding user conversions even where they are not allowed, and then discarding them afterward as invalid, but keeping a record that they existed. There is also a stronger mode (`UDC_Skip`) for skipping the search for user-defined conversions outright, which matches the old behavior and is retained to prevent infinite recursions. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D74009 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Overload.h clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaCodeComplete.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaInit.cpp clang/lib/Sema/SemaLookup.cpp clang/lib/Sema/SemaOpenMP.cpp clang/lib/Sema/SemaOverload.cpp clang/test/CXX/drs/dr0xx.cpp clang/test/SemaCXX/user-defined-conversions.cpp
Index: clang/test/SemaCXX/user-defined-conversions.cpp =================================================================== --- clang/test/SemaCXX/user-defined-conversions.cpp +++ 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); +} Index: clang/test/CXX/drs/dr0xx.cpp =================================================================== --- clang/test/CXX/drs/dr0xx.cpp +++ 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; Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ 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<InitListExpr>(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<InitListExpr>(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<Expr *> 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<Expr *> 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<CXXRecordDecl>(FunTmpl->getDeclContext()), ExplicitTemplateArgs, ObjectType, ObjectClassification, - FunctionArgs, CandidateSet, SuppressUserConversions, + FunctionArgs, CandidateSet, UserConversions, PartialOverloading); } else { AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), cast<CXXMethodDecl>(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<Expr *> Args, OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions, + UserDefinedConversionsKind UserConversions, OverloadCandidateParamOrder PO) { NamedDecl *Decl = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(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<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, - SuppressUserConversions, false, None, PO); + UserConversions, false, None, PO); } } @@ -6729,7 +6763,7 @@ Expr::Classification ObjectClassification, ArrayRef<Expr *> 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<Expr *> 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<QualType> 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<CXXMethodDecl>(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<Expr *> 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<QualType> 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<QualType> ParamTypes, ArrayRef<Expr *> 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<FunctionTemplateDecl>(*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<FunctionTemplateDecl>(Callee)) { S.AddTemplateOverloadCandidate(FuncTemplate, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet, - /*SuppressUserConversions=*/false, + Sema::UDC_Allow, PartialOverloading); return; } @@ -13897,7 +13948,7 @@ if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) { AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, CandidateSet, - /*SuppressUserConversions*/ false); + Sema::UDC_Allow); } else if ((Method = dyn_cast<CXXMethodDecl>(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<FunctionTemplateDecl>(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); Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ 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, Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -3247,27 +3247,29 @@ if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(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<FunctionTemplateDecl>(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<UsingDecl>(Cand.getDecl()) && "illegal Kind of operator = Decl"); Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ 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<InitListExpr>(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); Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -2235,14 +2235,13 @@ if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { S.AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, - Candidates, - /*SuppressUserConversions=*/false); + Candidates, Sema::UDC_Allow); continue; } FunctionDecl *Fn = cast<FunctionDecl>(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<FunctionTemplateDecl>(D)) { S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, - Candidates, - /*SuppressUserConversions=*/false); + Candidates, Sema::UDC_Allow); continue; } FunctionDecl *Fn = cast<FunctionDecl>(D); - S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, Candidates, - /*SuppressUserConversions=*/false); + S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, + Candidates, Sema::UDC_Allow); } SourceRange Range = TheCall->getSourceRange(); Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ 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, Index: clang/lib/Sema/SemaCodeComplete.cpp =================================================================== --- clang/lib/Sema/SemaCodeComplete.cpp +++ 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<Expr *, 12> 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<FunctionDecl>(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<FunctionTemplateDecl>(C)) { AddTemplateOverloadCandidate( FTD, DeclAccessPair::make(FTD, C->getAccess()), - /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet, - /*SuppressUserConversions=*/false, + /*ExplicitTemplateArgs=*/nullptr, Args, + CandidateSet, UDC_Allow, /*PartialOverloading=*/true); } } Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ 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<Expr *> Args, OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions = false, + UserDefinedConversionsKind UserConversions + = UDC_Allow, bool PartialOverloading = false, bool AllowExplicit = true, bool AllowExplicitConversion = false, @@ -3159,7 +3170,7 @@ ArrayRef<Expr *> 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<Expr *> 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<Expr *> 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<Expr *> Args, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, + UserDefinedConversionsKind UserConversions + = UDC_Allow, bool PartialOverloading = false, OverloadCandidateParamOrder PO = {}); void AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> 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<QualType> ParamTypes, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, - ConversionSequenceList &Conversions, bool SuppressUserConversions, + ConversionSequenceList &Conversions, + UserDefinedConversionsKind UserConversions, CXXRecordDecl *ActingContext = nullptr, QualType ObjectType = QualType(), Expr::Classification ObjectClassification = {}, OverloadCandidateParamOrder PO = {}); Index: clang/include/clang/Sema/Overload.h =================================================================== --- clang/include/clang/Sema/Overload.h +++ 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, Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ 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 "
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits