summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorGauthier Harnisch <tyker1@outlook.com>2019-06-14 08:56:20 +0000
committerGauthier Harnisch <tyker1@outlook.com>2019-06-14 08:56:20 +0000
commit17feca48a8331dd511992e3ef0876486e774deec (patch)
treed546e1c31de0d15580261c72cafd1d9fa7aaf424 /lib/Sema
parent4a58b8483cde0d2ea84c2ad9741c83b45ede8f55 (diff)
downloadclang-17feca48a8331dd511992e3ef0876486e774deec.tar.gz
[C++20] add Basic consteval specifier
Summary: this revision adds Lexing, Parsing and Basic Semantic for the consteval specifier as specified by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1073r3.html with this patch, the consteval specifier is treated as constexpr but can only be applied to function declaration. Changes: - add the consteval keyword. - add parsing of consteval specifier for normal declarations and lambdas expressions. - add the whether a declaration is constexpr is now represented by and enum everywhere except for variable because they can't be consteval. - adapt diagnostic about constexpr to print constexpr or consteval depending on the case. - add tests for basic semantic. Reviewers: rsmith, martong, shafik Reviewed By: rsmith Subscribers: eraman, efriedma, rnkovacs, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D61790 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@363362 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/DeclSpec.cpp25
-rw-r--r--lib/Sema/SemaCoroutine.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp60
-rw-r--r--lib/Sema/SemaDeclAttr.cpp10
-rw-r--r--lib/Sema/SemaDeclCXX.cpp68
-rw-r--r--lib/Sema/SemaExpr.cpp12
-rw-r--r--lib/Sema/SemaLambda.cpp37
-rw-r--r--lib/Sema/SemaStmt.cpp3
-rw-r--r--lib/Sema/SemaTemplate.cpp6
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp8
-rw-r--r--lib/Sema/SemaType.cpp2
-rw-r--r--lib/Sema/TreeTransform.h2
12 files changed, 133 insertions, 103 deletions
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 08c3b0ff32..21d7f6bd42 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -564,6 +564,15 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
llvm_unreachable("Unknown typespec!");
}
+const char *DeclSpec::getSpecifierName(ConstexprSpecKind C) {
+ switch (C) {
+ case CSK_unspecified: return "unspecified";
+ case CSK_constexpr: return "constexpr";
+ case CSK_consteval: return "consteval";
+ }
+ llvm_unreachable("Unknown ConstexprSpecKind");
+}
+
const char *DeclSpec::getSpecifierName(TQ T) {
switch (T) {
case DeclSpec::TQ_unspecified: return "unspecified";
@@ -1025,16 +1034,17 @@ bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
return false;
}
-bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
+bool DeclSpec::SetConstexprSpec(ConstexprSpecKind ConstexprKind,
+ SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
- // 'constexpr constexpr' is ok, but warn as this is likely not what the user
- // intended.
- if (Constexpr_specified) {
+ if (ConstexprSpecifier != CSK_unspecified) {
+ if (ConstexprSpecifier == CSK_consteval || ConstexprKind == CSK_consteval)
+ return BadSpecifier(ConstexprKind, ConstexprSpecifier, PrevSpec, DiagID);
DiagID = diag::warn_duplicate_declspec;
PrevSpec = "constexpr";
return true;
}
- Constexpr_specified = true;
+ ConstexprSpecifier = ConstexprKind;
ConstexprLoc = Loc;
return false;
}
@@ -1280,9 +1290,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
else if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32)
S.Diag(TSTLoc, diag::warn_cxx98_compat_unicode_type)
<< (TypeSpecType == TST_char16 ? "char16_t" : "char32_t");
- if (Constexpr_specified)
+ if (getConstexprSpecifier() == CSK_constexpr)
S.Diag(ConstexprLoc, diag::warn_cxx98_compat_constexpr);
-
+ if (getConstexprSpecifier() == CSK_consteval)
+ S.Diag(ConstexprLoc, diag::warn_cxx20_compat_consteval);
// C++ [class.friend]p6:
// No storage-class-specifier shall appear in the decl-specifier-seq
// of a friend declaration.
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index dc259fe03f..fc6470617c 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -210,6 +210,7 @@ static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
DiagConstexpr,
DiagAutoRet,
DiagVarargs,
+ DiagConsteval,
};
bool Diagnosed = false;
auto DiagInvalid = [&](InvalidFuncDiag ID) {
@@ -244,7 +245,7 @@ static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
// evaluation of e [...] would evaluate one of the following expressions:
// [...] an await-expression [...] a yield-expression."
if (FD->isConstexpr())
- DiagInvalid(DiagConstexpr);
+ DiagInvalid(FD->isConsteval() ? DiagConsteval : DiagConstexpr);
// [dcl.spec.auto]p15: "A function declared with a return type that uses a
// placeholder type shall not be a coroutine."
if (FD->getReturnType()->isUndeducedType())
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 10837f6894..ce6fd41236 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4292,14 +4292,18 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
<< getLangOpts().CPlusPlus17;
- if (DS.isConstexprSpecified()) {
+ if (DS.hasConstexprSpecifier()) {
// C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations
// and definitions of functions and variables.
+ // C++2a [dcl.constexpr]p1: The consteval specifier shall be applied only to
+ // the declaration of a function or function template
+ bool IsConsteval = DS.getConstexprSpecifier() == CSK_consteval;
if (Tag)
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag)
- << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType());
+ << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << IsConsteval;
else
- Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators);
+ Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_wrong_decl_kind)
+ << IsConsteval;
// Don't emit warnings after this error.
return TagD;
}
@@ -5752,9 +5756,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getDeclSpec().isInlineSpecified())
Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
<< getLangOpts().CPlusPlus17;
- if (D.getDeclSpec().isConstexprSpecified())
+ if (D.getDeclSpec().hasConstexprSpecifier())
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 1;
+ << 1 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval);
if (D.getName().Kind != UnqualifiedIdKind::IK_Identifier) {
if (D.getName().Kind == UnqualifiedIdKind::IK_DeductionGuideName)
@@ -6648,13 +6652,17 @@ NamedDecl *Sema::ActOnVariableDeclarator(
NewVD->setTemplateParameterListsInfo(
Context, TemplateParamLists.drop_back(VDTemplateParamLists));
- if (D.getDeclSpec().isConstexprSpecified()) {
+ if (D.getDeclSpec().hasConstexprSpecifier()) {
NewVD->setConstexpr(true);
// C++1z [dcl.spec.constexpr]p1:
// A static data member declared with the constexpr specifier is
// implicitly an inline variable.
if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus17)
NewVD->setImplicitlyInline();
+ if (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval)
+ Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_constexpr_wrong_decl_kind)
+ << /*consteval*/ 1;
}
}
@@ -7982,7 +7990,8 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
(!R->getAsAdjusted<FunctionType>() && R->isFunctionProtoType());
NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
- R, TInfo, SC, isInline, HasPrototype, false);
+ R, TInfo, SC, isInline, HasPrototype,
+ CSK_unspecified);
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -7990,8 +7999,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
- bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
-
+ ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
@@ -8010,7 +8018,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return CXXConstructorDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
TInfo, ExplicitSpecifier, isInline,
- /*isImplicitlyDeclared=*/false, isConstexpr);
+ /*isImplicitlyDeclared=*/false, ConstexprKind);
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
// This is a C++ destructor declaration.
@@ -8040,7 +8048,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
D.getIdentifierLoc(), Name, R, TInfo, SC,
isInline,
- /*hasPrototype=*/true, isConstexpr);
+ /*hasPrototype=*/true, ConstexprKind);
}
} else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
@@ -8054,7 +8062,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
IsVirtualOkay = true;
return CXXConversionDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, isInline, ExplicitSpecifier, isConstexpr, SourceLocation());
+ TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation());
} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
@@ -8078,7 +8086,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// This is a C++ method declaration.
CXXMethodDecl *Ret = CXXMethodDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, SC, isInline, isConstexpr, SourceLocation());
+ TInfo, SC, isInline, ConstexprKind, SourceLocation());
IsVirtualOkay = !Ret->isStatic();
return Ret;
} else {
@@ -8092,7 +8100,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// - we're in C++ (where every function has a prototype),
return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
R, TInfo, SC, isInline, true /*HasPrototype*/,
- isConstexpr);
+ ConstexprKind);
}
}
@@ -8422,7 +8430,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
- bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
+ ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
isFriend = D.getDeclSpec().isFriendSpecified();
if (isFriend && !isInline && D.isFunctionDefinition()) {
// C++ [class.friend]p5
@@ -8621,7 +8629,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- if (isConstexpr) {
+ if (ConstexprKind != CSK_unspecified) {
// C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
// are implicitly inline.
NewFD->setImplicitlyInline();
@@ -8630,7 +8638,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// be either constructors or to return a literal type. Therefore,
// destructors cannot be declared constexpr.
if (isa<CXXDestructorDecl>(NewFD))
- Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor);
+ Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor)
+ << (ConstexprKind == CSK_consteval);
}
// If __module_private__ was specified, mark the function accordingly.
@@ -9527,6 +9536,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
DeletedFuncs = 5,
DefaultedFuncs = 6,
ConstexprFuncs = 7,
+ ConstevalFuncs = 8,
};
enum Different {
CallingConv = 0,
@@ -9602,7 +9612,8 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
if (NewFD->isConstexpr() && (MVType == MultiVersionKind::CPUDispatch ||
MVType == MultiVersionKind::CPUSpecific))
return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << ConstexprFuncs;
+ << IsCPUSpecificCPUDispatchMVType
+ << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType());
const auto *NewType = cast<FunctionType>(NewQType);
@@ -9633,7 +9644,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
<< ReturnType;
- if (OldFD->isConstexpr() != NewFD->isConstexpr())
+ if (OldFD->getConstexprKind() != NewFD->getConstexprKind())
return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
<< ConstexprSpec;
@@ -10383,8 +10394,9 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
}
if (FD->isConstexpr()) {
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main)
- << FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
- FD->setConstexpr(false);
+ << FD->isConsteval()
+ << FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
+ FD->setConstexprKind(CSK_unspecified);
}
if (getLangOpts().OpenCL) {
@@ -12475,9 +12487,9 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (DS.isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
<< getLangOpts().CPlusPlus17;
- if (DS.isConstexprSpecified())
+ if (DS.hasConstexprSpecifier())
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 0;
+ << 0 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval);
DiagnoseFunctionSpecifiers(DS);
@@ -13128,7 +13140,7 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
bool Sema::canDelayFunctionBody(const Declarator &D) {
// We can't delay parsing the body of a constexpr function template (yet).
- if (D.getDeclSpec().isConstexprSpecified())
+ if (D.getDeclSpec().hasConstexprSpecifier())
return false;
// We can't delay parsing the body of a function template with a deduced
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 932cb18a93..c32653c5d2 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -7460,12 +7460,10 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
// FIXME: Mangling?
// FIXME: Is the qualifier info correct?
// FIXME: Is the DeclContext correct?
- NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
- Loc, Loc, DeclarationName(II),
- FD->getType(), FD->getTypeSourceInfo(),
- SC_None, false/*isInlineSpecified*/,
- FD->hasPrototype(),
- false/*isConstexprSpecified*/);
+ NewFD = FunctionDecl::Create(
+ FD->getASTContext(), FD->getDeclContext(), Loc, Loc,
+ DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None,
+ false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified);
NewD = NewFD;
if (FD->getQualifier())
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 354316a3cc..6686b855c3 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -638,9 +638,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// C++11 [dcl.constexpr]p1: If any declaration of a function or function
// template has a constexpr specifier then all its declarations shall
// contain the constexpr specifier.
- if (New->isConstexpr() != Old->isConstexpr()) {
+ if (New->getConstexprKind() != Old->getConstexprKind()) {
Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
- << New << New->isConstexpr();
+ << New << New->getConstexprKind() << Old->getConstexprKind();
Diag(Old->getLocation(), diag::note_previous_declaration);
Invalid = true;
} else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
@@ -741,8 +741,9 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
CPlusPlus20Specifiers.push_back(DeclSpec::getSpecifierName(TSCS));
CPlusPlus20SpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc());
}
- if (DS.isConstexprSpecified()) {
- BadSpecifiers.push_back("constexpr");
+ if (DS.hasConstexprSpecifier()) {
+ BadSpecifiers.push_back(
+ DeclSpec::getSpecifierName(DS.getConstexprSpecifier()));
BadSpecifierLocs.push_back(DS.getConstexprSpecLoc());
}
if (DS.isInlineSpecified()) {
@@ -1581,10 +1582,10 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
SourceLocation ParamLoc = PD->getLocation();
if (!(*i)->isDependentType() &&
- SemaRef.RequireLiteralType(ParamLoc, *i,
- diag::err_constexpr_non_literal_param,
- ArgIndex+1, PD->getSourceRange(),
- isa<CXXConstructorDecl>(FD)))
+ SemaRef.RequireLiteralType(
+ ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1,
+ PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
+ FD->isConsteval()))
return false;
}
return true;
@@ -1661,7 +1662,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
QualType RT = NewFD->getReturnType();
if (!RT->isDependentType() &&
RequireLiteralType(NewFD->getLocation(), RT,
- diag::err_constexpr_non_literal_return))
+ diag::err_constexpr_non_literal_return,
+ NewFD->isConsteval()))
return false;
}
@@ -1775,7 +1777,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
default:
SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl);
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
return false;
}
}
@@ -1960,7 +1962,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
}
SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl);
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
return false;
}
@@ -2082,7 +2084,8 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
Dcl->getReturnType()->isDependentType());
Diag(Dcl->getLocation(),
OK ? diag::warn_cxx11_compat_constexpr_body_no_return
- : diag::err_constexpr_body_no_return);
+ : diag::err_constexpr_body_no_return)
+ << Dcl->isConsteval();
if (!OK)
return false;
} else if (ReturnStmts.size() > 1) {
@@ -3052,7 +3055,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
DS.getStorageClassSpec() == DeclSpec::SCS_mutable) &&
!isFunc);
- if (DS.isConstexprSpecified() && isInstField) {
+ if (DS.hasConstexprSpecifier() && isInstField) {
SemaDiagnosticBuilder B =
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr_member);
SourceLocation ConstexprLoc = DS.getConstexprSpecLoc();
@@ -6688,7 +6691,10 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
: isa<CXXConstructorDecl>(MD)) &&
MD->isConstexpr() && !Constexpr &&
MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr) << CSM;
+ Diag(MD->getBeginLoc(), MD->isConsteval()
+ ? diag::err_incorrect_defaulted_consteval
+ : diag::err_incorrect_defaulted_constexpr)
+ << CSM;
// FIXME: Explain why the special member can't be constexpr.
HadError = true;
}
@@ -6698,7 +6704,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// If a function is explicitly defaulted on its first declaration, it is
// implicitly considered to be constexpr if the implicit declaration
// would be.
- MD->setConstexpr(Constexpr);
+ MD->setConstexprKind(Constexpr ? CSK_constexpr : CSK_unspecified);
if (!Type->hasExceptionSpec()) {
// C++2a [except.spec]p3:
@@ -8744,7 +8750,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
// We leave 'friend' and 'virtual' to be rejected in the normal way.
if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() ||
DS.getStorageClassSpecLoc().isValid() || DS.isInlineSpecified() ||
- DS.isNoreturnSpecified() || DS.isConstexprSpecified()) {
+ DS.isNoreturnSpecified() || DS.hasConstexprSpecifier()) {
BadSpecifierDiagnoser Diagnoser(
*this, D.getIdentifierLoc(),
diag::err_deduction_guide_invalid_specifier);
@@ -11035,7 +11041,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(),
/*TInfo=*/nullptr, ExplicitSpecifier(),
- /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr);
+ /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+ Constexpr ? CSK_constexpr : CSK_unspecified);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
@@ -11155,7 +11162,8 @@ Sema::findInheritingConstructor(SourceLocation Loc,
CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
BaseCtor->getExplicitSpecifier(), /*Inline=*/true,
- /*ImplicitlyDeclared=*/true, Constexpr,
+ /*ImplicitlyDeclared=*/true,
+ Constexpr ? BaseCtor->getConstexprKind() : CSK_unspecified,
InheritedConstructor(Shadow, BaseCtor));
if (Shadow->isInvalidDecl())
DerivedCtor->setInvalidDecl();
@@ -11904,10 +11912,11 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXMethodDecl *CopyAssignment =
- CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
- /*isInline=*/true, Constexpr, SourceLocation());
+ CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo, QualType(),
+ /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
+ /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified,
+ SourceLocation());
CopyAssignment->setAccess(AS_public);
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
@@ -12224,10 +12233,11 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXMethodDecl *MoveAssignment =
- CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
- /*isInline=*/true, Constexpr, SourceLocation());
+ CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo, QualType(),
+ /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
+ /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified,
+ SourceLocation());
MoveAssignment->setAccess(AS_public);
MoveAssignment->setDefaulted();
MoveAssignment->setImplicit();
@@ -12608,7 +12618,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
ExplicitSpecifier(),
/*isInline=*/true,
- /*isImplicitlyDeclared=*/true, Constexpr);
+ /*isImplicitlyDeclared=*/true,
+ Constexpr ? CSK_constexpr : CSK_unspecified);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
@@ -12739,7 +12750,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
ExplicitSpecifier(),
/*isInline=*/true,
- /*isImplicitlyDeclared=*/true, Constexpr);
+ /*isImplicitlyDeclared=*/true,
+ Constexpr ? CSK_constexpr : CSK_unspecified);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d444a35be8..a8f3ec0ba5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -17125,13 +17125,11 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
if (DRE && Proto && Proto->getParamTypes().empty() && Proto->isVariadic()) {
SourceLocation Loc = FD->getLocation();
- FunctionDecl *NewFD = FunctionDecl::Create(S.Context,
- FD->getDeclContext(),
- Loc, Loc, FD->getNameInfo().getName(),
- DestType, FD->getTypeSourceInfo(),
- SC_None, false/*isInlineSpecified*/,
- FD->hasPrototype(),
- false/*isConstexprSpecified*/);
+ FunctionDecl *NewFD = FunctionDecl::Create(
+ S.Context, FD->getDeclContext(), Loc, Loc,
+ FD->getNameInfo().getName(), DestType, FD->getTypeSourceInfo(),
+ SC_None, false /*isInlineSpecified*/, FD->hasPrototype(),
+ /*ConstexprKind*/ CSK_unspecified);
if (FD->getQualifier())
NewFD->setQualifierInfo(FD->getQualifierLoc());
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index ccc8f6f42a..268e15c20e 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -370,7 +370,7 @@ Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext(
CXXMethodDecl *Sema::startLambdaDefinition(
CXXRecordDecl *Class, SourceRange IntroducerRange,
TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params, const bool IsConstexprSpecified,
+ ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind,
Optional<std::pair<unsigned, Decl *>> Mangling) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
@@ -400,16 +400,12 @@ CXXMethodDecl *Sema::startLambdaDefinition(
= IntroducerRange.getBegin().getRawEncoding();
MethodNameLoc.CXXOperatorName.EndOpNameLoc
= IntroducerRange.getEnd().getRawEncoding();
- CXXMethodDecl *Method
- = CXXMethodDecl::Create(Context, Class, EndLoc,
- DeclarationNameInfo(MethodName,
- IntroducerRange.getBegin(),
- MethodNameLoc),
- MethodType, MethodTypeInfo,
- SC_None,
- /*isInline=*/true,
- IsConstexprSpecified,
- EndLoc);
+ CXXMethodDecl *Method = CXXMethodDecl::Create(
+ Context, Class, EndLoc,
+ DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
+ MethodNameLoc),
+ MethodType, MethodTypeInfo, SC_None,
+ /*isInline=*/true, ConstexprKind, EndLoc);
Method->setAccess(AS_public);
// Temporarily set the lexical declaration context to the current
@@ -940,7 +936,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
- ParamInfo.getDeclSpec().isConstexprSpecified());
+ ParamInfo.getDeclSpec().getConstexprSpecifier());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -1341,7 +1337,7 @@ static void addFunctionPointerConversion(Sema &S,
S.Context, Class, Loc,
DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI,
/*isInline=*/true, ExplicitSpecifier(),
- /*isConstexpr=*/S.getLangOpts().CPlusPlus17,
+ S.getLangOpts().CPlusPlus17 ? CSK_constexpr : CSK_unspecified,
CallOperator->getBody()->getEndLoc());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
@@ -1380,8 +1376,7 @@ static void addFunctionPointerConversion(Sema &S,
CXXMethodDecl *Invoke = CXXMethodDecl::Create(
S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
- /*IsInline=*/true,
- /*IsConstexpr=*/false, CallOperator->getBody()->getEndLoc());
+ /*IsInline=*/true, CSK_unspecified, CallOperator->getBody()->getEndLoc());
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
InvokerParams[I]->setOwningFunction(Invoke);
Invoke->setParams(InvokerParams);
@@ -1427,8 +1422,8 @@ static void addBlockPointerConversion(Sema &S,
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy,
S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
- /*isInline=*/true, ExplicitSpecifier(),
- /*isConstexpr=*/false, CallOperator->getBody()->getEndLoc());
+ /*isInline=*/true, ExplicitSpecifier(), CSK_unspecified,
+ CallOperator->getBody()->getEndLoc());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
Class->addDecl(Conversion);
@@ -1782,9 +1777,11 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
!Class->getDeclContext()->isDependentContext()) {
TentativeAnalysisScope DiagnosticScopeGuard(*this);
- CallOperator->setConstexpr(
- CheckConstexprFunctionDecl(CallOperator) &&
- CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()));
+ CallOperator->setConstexprKind(
+ (CheckConstexprFunctionDecl(CallOperator) &&
+ CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()))
+ ? CSK_constexpr
+ : CSK_unspecified);
}
// Emit delayed shadowing warnings now that the full capture list is known.
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index bc1e8f2709..3b149e6fdb 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -3693,7 +3693,8 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (FD)
- Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
+ Diag(ReturnLoc, DiagID)
+ << FD->getIdentifier() << 0 /*fn*/ << FD->isConsteval();
else
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f7f3ccc3e2..03240655ee 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1147,7 +1147,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
// variable or variable template or the declaration of a function or
// function template.
- if (DS.isConstexprSpecified())
+ if (DS.hasConstexprSpecifier())
EmitDiag(DS.getConstexprSpecLoc());
// [dcl.fct.spec]p1:
@@ -8371,7 +8371,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
// FIXME: We need an update record for this AST mutation.
// FIXME: What if there are multiple such prior declarations (for instance,
// from different modules)?
- Specialization->setConstexpr(FD->isConstexpr());
+ Specialization->setConstexprKind(FD->getConstexprKind());
}
// FIXME: Check if the prior specialization has a point of instantiation.
@@ -9260,7 +9260,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::err_explicit_instantiation_inline :
diag::warn_explicit_instantiation_inline_0x)
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
- if (D.getDeclSpec().isConstexprSpecified() && R->isFunctionType())
+ if (D.getDeclSpec().hasConstexprSpecifier() && R->isFunctionType())
// FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is
// not already specified.
Diag(D.getDeclSpec().getConstexprSpecLoc(),
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d0ff0994ed..cbfb0fed23 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1779,7 +1779,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Function = FunctionDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo,
D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
- D->hasWrittenPrototype(), D->isConstexpr());
+ D->hasWrittenPrototype(), D->getConstexprKind());
Function->setRangeEnd(D->getSourceRange().getEnd());
}
@@ -2087,7 +2087,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
Method = CXXConstructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false,
- Constructor->isConstexpr());
+ Constructor->getConstexprKind());
Method->setRangeEnd(Constructor->getEndLoc());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
@@ -2099,12 +2099,12 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
Method = CXXConversionDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier,
- Conversion->isConstexpr(), Conversion->getEndLoc());
+ Conversion->getConstexprKind(), Conversion->getEndLoc());
} else {
StorageClass SC = D->isStatic() ? SC_Static : SC_None;
Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo,
T, TInfo, SC, D->isInlineSpecified(),
- D->isConstexpr(), D->getEndLoc());
+ D->getConstexprKind(), D->getEndLoc());
}
if (D->isInlined())
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 47de398d4f..88b544068a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -5146,7 +5146,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++0x [dcl.constexpr]p9:
// A constexpr specifier used in an object declaration declares the object
// as const.
- if (D.getDeclSpec().isConstexprSpecified() && T->isObjectType()) {
+ if (D.getDeclSpec().hasConstexprSpecifier() && T->isObjectType()) {
T.addConst();
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 6e033cb579..65f8678d94 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -11337,7 +11337,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
Class, E->getIntroducerRange(), NewCallOpTSI,
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
- E->getCallOperator()->isConstexpr(), Mangling);
+ E->getCallOperator()->getConstexprKind(), Mangling);
LSI->CallOperator = NewCallOperator;