summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorNicolas Lesser <blitzrakete@gmail.com>2019-05-04 00:09:00 +0000
committerNicolas Lesser <blitzrakete@gmail.com>2019-05-04 00:09:00 +0000
commit6de0b449c07ec7adbcb34e7c94c544ee37ef5963 (patch)
tree0e2112dbbe57b79622f5a7708add8fecc6a75b80 /lib/Sema/SemaOverload.cpp
parent6cc60c9164a96f1d73ccfd302303490e0d085b87 (diff)
downloadclang-6de0b449c07ec7adbcb34e7c94c544ee37ef5963.tar.gz
[clang] adding explicit(bool) from c++2a
this patch adds support for the explicit bool specifier. Changes: - The parsing for the explicit(bool) specifier was added in ParseDecl.cpp. - The storage of the explicit specifier was changed. the explicit specifier was stored as a boolean value in the FunctionDeclBitfields and in the DeclSpec class. now it is stored as a PointerIntPair<Expr*, 2> with a flag and a potential expression in CXXConstructorDecl, CXXDeductionGuideDecl, CXXConversionDecl and in the DeclSpec class. - Following the AST change, Serialization, ASTMatchers, ASTComparator and ASTPrinter were adapted. - Template instantiation was adapted to instantiate the potential expressions of the explicit(bool) specifier When instantiating their associated declaration. - The Add*Candidate functions were adapted, they now take a Boolean indicating if the context allowing explicit constructor or conversion function and this boolean is used to remove invalid overloads that required template instantiation to be detected. - Test for Semantic and Serialization were added. This patch is not yet complete. I still need to check that interaction with CTAD and deduction guides is correct. and add more tests for AST operations. But I wanted first feedback. Perhaps this patch should be spited in smaller patches, but making each patch testable as a standalone may be tricky. Patch by Tyker Differential Revision: https://reviews.llvm.org/D60934 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359949 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r--lib/Sema/SemaOverload.cpp173
1 files changed, 110 insertions, 63 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index df979b68b6..1ef932e05e 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*/ false, ADLCallKind::UsesADL);
} else {
- AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl,
- ExplicitTemplateArgs, Args, CandidateSet,
- /*SupressUserConversions=*/false,
- PartialOverloading, ADLCallKind::UsesADL);
+ AddTemplateOverloadCandidate(
+ cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args,
+ CandidateSet,
+ /*SupressUserConversions=*/false, PartialOverloading,
+ /*AllowExplicit*/ false, 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,11 @@ 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,
+ /*PartialOverloading*/ false,
+ /*AllowExplicit*/ true);
} else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
// If explicit template arguments were provided, we can't call a
// non-template member function.