diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-09 03:59:21 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-09 03:59:21 +0000 |
commit | 7a6d690bb52df60e979a7c7f9d03a774009bb443 (patch) | |
tree | d7e8e354720db8f569f17d421af83536ecfb4ebe /lib/Sema/SemaOverload.cpp | |
parent | b14b99abefb0dd40b13dd70c99d87d04a66b3236 (diff) | |
download | clang-7a6d690bb52df60e979a7c7f9d03a774009bb443.tar.gz |
[c++20] Add support for explicit(bool), as described in P0892R2.
Patch by Tyker!
Differential Revision: https://reviews.llvm.org/D60934
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@360311 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 171 |
1 files changed, 108 insertions, 63 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 19ac2bf33a..74283a067c 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3242,10 +3242,13 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, From, - CandidateSet, SuppressUserConversions); + CandidateSet, SuppressUserConversions, + /*PartialOverloading*/ false, + AllowExplicit); else S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From, - CandidateSet, SuppressUserConversions); + CandidateSet, SuppressUserConversions, + /*PartialOverloading*/ false, AllowExplicit); } } @@ -3372,13 +3375,15 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, S.AddTemplateOverloadCandidate( Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs), - CandidateSet, SuppressUserConversions); + CandidateSet, SuppressUserConversions, + /*PartialOverloading*/ false, AllowExplicit); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, llvm::makeArrayRef(Args, NumArgs), - CandidateSet, SuppressUserConversions); + CandidateSet, SuppressUserConversions, + /*PartialOverloading*/ false, AllowExplicit); } } } @@ -3410,14 +3415,13 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, FoundDecl, - ActingContext, From, ToType, - CandidateSet, - AllowObjCConversionOnExplicit); + S.AddTemplateConversionCandidate( + ConvTemplate, FoundDecl, ActingContext, From, ToType, + CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit); else - S.AddConversionCandidate(Conv, FoundDecl, ActingContext, - From, ToType, CandidateSet, - AllowObjCConversionOnExplicit); + S.AddConversionCandidate( + Conv, FoundDecl, ActingContext, From, ToType, CandidateSet, + AllowObjCConversionOnExplicit, AllowExplicit); } } } @@ -4445,13 +4449,13 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, } if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, - Init, DeclType, CandidateSet, - /*AllowObjCConversionOnExplicit=*/false); + S.AddTemplateConversionCandidate( + ConvTemplate, I.getPair(), ActingDC, Init, DeclType, CandidateSet, + /*AllowObjCConversionOnExplicit=*/false, AllowExplicit); else - S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, - DeclType, CandidateSet, - /*AllowObjCConversionOnExplicit=*/false); + S.AddConversionCandidate( + Conv, I.getPair(), ActingDC, Init, DeclType, CandidateSet, + /*AllowObjCConversionOnExplicit=*/false, AllowExplicit); } bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -5414,7 +5418,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, // condition shall be a contextually converted constant expression of type // bool. ImplicitConversionSequence ICS = - CCE == Sema::CCEK_ConstexprIf + CCE == Sema::CCEK_ConstexprIf || CCE == Sema::CCEK_ExplicitBool ? TryContextuallyConvertToBool(S, From) : TryCopyInitialization(S, From, T, /*SuppressUserConversions=*/false, @@ -5730,12 +5734,13 @@ collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType, if (ConvTemplate) SemaRef.AddTemplateConversionCandidate( - ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet, - /*AllowObjCConversionOnExplicit=*/false); + ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet, + /*AllowObjCConversionOnExplicit=*/false, /*AllowExplicit*/ true); else SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From, ToType, CandidateSet, - /*AllowObjCConversionOnExplicit=*/false); + /*AllowObjCConversionOnExplicit=*/false, + /*AllowExplicit*/ true); } } @@ -5987,13 +5992,11 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context, /// \param PartialOverloading true if we are performing "partial" overloading /// based on an incomplete set of function arguments. This feature is used by /// code completion. -void Sema::AddOverloadCandidate(FunctionDecl *Function, - DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, - OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions, - bool PartialOverloading, bool AllowExplicit, - ADLCallKind IsADLCandidate, - ConversionSequenceList EarlyConversions) { +void Sema::AddOverloadCandidate( + FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions, + ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions) { const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -6150,13 +6153,11 @@ void Sema::AddOverloadCandidate(FunctionDecl *Function, // (13.3.3.1) that converts that argument to the corresponding // parameter of F. QualType ParamType = Proto->getParamType(ArgIdx); - Candidate.Conversions[ArgIdx] - = TryCopyInitialization(*this, Args[ArgIdx], ParamType, - SuppressUserConversions, - /*InOverloadResolution=*/true, - /*AllowObjCWritebackConversion=*/ - getLangOpts().ObjCAutoRefCount, - AllowExplicit); + Candidate.Conversions[ArgIdx] = TryCopyInitialization( + *this, Args[ArgIdx], ParamType, SuppressUserConversions, + /*InOverloadResolution=*/true, + /*AllowObjCWritebackConversion=*/ + getLangOpts().ObjCAutoRefCount, AllowExplicitConversions); if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -6170,6 +6171,15 @@ void Sema::AddOverloadCandidate(FunctionDecl *Function, } } + if (!AllowExplicit) { + ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function); + if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_explicit_resolved; + return; + } + } + if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; @@ -6759,7 +6769,7 @@ void Sema::AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, - bool PartialOverloading, ADLCallKind IsADLCandidate) { + bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate) { if (!CandidateSet.isNewCandidate(FunctionTemplate)) return; @@ -6808,9 +6818,10 @@ void Sema::AddTemplateOverloadCandidate( // Add the function template specialization produced by template argument // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet, - SuppressUserConversions, PartialOverloading, - /*AllowExplicit*/ false, IsADLCandidate, Conversions); + AddOverloadCandidate( + Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, + PartialOverloading, AllowExplicit, + /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions); } /// Check that implicit conversion sequences can be formed for each argument @@ -6915,14 +6926,11 @@ static bool isAllowableExplicitConversion(Sema &S, /// and ToType is the type that we're eventually trying to convert to /// (which may or may not be the same type as the type that the /// conversion function produces). -void -Sema::AddConversionCandidate(CXXConversionDecl *Conversion, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, - Expr *From, QualType ToType, - OverloadCandidateSet& CandidateSet, - bool AllowObjCConversionOnExplicit, - bool AllowResultConversion) { +void Sema::AddConversionCandidate( + CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, + bool AllowExplicit, bool AllowResultConversion) { assert(!Conversion->getDescribedFunctionTemplate() && "Conversion function templates use AddTemplateConversionCandidate"); QualType ConvType = Conversion->getConversionType().getNonReferenceType(); @@ -7081,6 +7089,13 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, "Can only end up with a standard conversion sequence or failure"); } + if (!AllowExplicit && Conversion->getExplicitSpecifier().getKind() != + ExplicitSpecKind::ResolvedFalse) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_explicit_resolved; + return; + } + if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; @@ -7100,14 +7115,11 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /// to deduce the template arguments of the conversion function /// template from the type that we are converting to (C++ /// [temp.deduct.conv]). -void -Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingDC, - Expr *From, QualType ToType, - OverloadCandidateSet &CandidateSet, - bool AllowObjCConversionOnExplicit, - bool AllowResultConversion) { +void Sema::AddTemplateConversionCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingDC, Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, + bool AllowExplicit, bool AllowResultConversion) { assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) && "Only conversion function templates permitted here"); @@ -7137,7 +7149,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, assert(Specialization && "Missing function template specialization?"); AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType, CandidateSet, AllowObjCConversionOnExplicit, - AllowResultConversion); + AllowExplicit, AllowResultConversion); } /// AddSurrogateCandidate - Adds a "surrogate" candidate function that @@ -8991,12 +9003,14 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet, /*SupressUserConversions=*/false, PartialOverloading, - /*AllowExplicit=*/false, ADLCallKind::UsesADL); + /*AllowExplicitConversions*/ false, + /*AllowExplicit*/ true, ADLCallKind::UsesADL); } else { - AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl, - ExplicitTemplateArgs, Args, CandidateSet, - /*SupressUserConversions=*/false, - PartialOverloading, ADLCallKind::UsesADL); + AddTemplateOverloadCandidate( + cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args, + CandidateSet, + /*SuppressUserConversions=*/false, PartialOverloading, + /*AllowExplicit*/true, ADLCallKind::UsesADL); } } } @@ -10327,6 +10341,33 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) { << Attr->getCond()->getSourceRange() << Attr->getMessage(); } +static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) { + ExplicitSpecifier ES; + const char *DeclName; + switch (Cand->Function->getDeclKind()) { + case Decl::Kind::CXXConstructor: + ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier(); + DeclName = "constructor"; + break; + case Decl::Kind::CXXConversion: + ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier(); + DeclName = "conversion operator"; + break; + case Decl::Kind::CXXDeductionGuide: + ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier(); + DeclName = "deductiong guide"; + break; + default: + llvm_unreachable("invalid Decl"); + } + assert(ES.getExpr() && "null expression should be handled before"); + S.Diag(Cand->Function->getLocation(), + diag::note_ovl_candidate_explicit_forbidden) + << DeclName; + S.Diag(ES.getExpr()->getBeginLoc(), + diag::note_explicit_bool_resolved_to_true); +} + static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) { FunctionDecl *Callee = Cand->Function; @@ -10411,6 +10452,9 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_enable_if: return DiagnoseFailedEnableIfAttr(S, Cand); + case ovl_fail_explicit_resolved: + return DiagnoseFailedExplicitSpec(S, Cand); + case ovl_fail_ext_disabled: return DiagnoseOpenCLExtensionDisabled(S, Cand); @@ -12981,8 +13025,9 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Microsoft supports direct constructor calls. if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) { - AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), - Args, CandidateSet); + AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, + CandidateSet, + /*SuppressUserConversions*/ false); } else if ((Method = dyn_cast<CXXMethodDecl>(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. |