[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
llvm-svn: 363362
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index f2e552a..14151ef 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -109,7 +109,7 @@
// the tokens and store them for parsing at the end of the translation unit.
if (getLangOpts().DelayedTemplateParsing &&
D.getFunctionDefinitionKind() == FDK_Definition &&
- !D.getDeclSpec().isConstexprSpecified() &&
+ !D.getDeclSpec().hasConstexprSpecifier() &&
!(FnD && FnD->getAsFunction() &&
FnD->getAsFunction()->getReturnType()->getContainedAutoType()) &&
((Actions.CurContext->isDependentContext() ||
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 5589297..2c9045d 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2487,8 +2487,9 @@
}
// Issue diagnostic and remove constexpr specifier if present.
- if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) {
- Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
+ if (DS.hasConstexprSpecifier() && DSC != DeclSpecContext::DSC_condition) {
+ Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr)
+ << (DS.getConstexprSpecifier() == CSK_consteval);
DS.ClearConstexprSpec();
}
}
@@ -3626,7 +3627,12 @@
// constexpr
case tok::kw_constexpr:
- isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetConstexprSpec(CSK_constexpr, Loc, PrevSpec, DiagID);
+ break;
+
+ // consteval
+ case tok::kw_consteval:
+ isInvalid = DS.SetConstexprSpec(CSK_consteval, Loc, PrevSpec, DiagID);
break;
// type-specifier
@@ -5031,6 +5037,9 @@
case tok::annot_decltype:
case tok::kw_constexpr:
+ // C++20 consteval.
+ case tok::kw_consteval:
+
// C11 _Atomic
case tok::kw__Atomic:
return true;
@@ -6267,7 +6276,7 @@
Actions.CurContext->isRecord());
Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers());
- if (D.getDeclSpec().isConstexprSpecified() && !getLangOpts().CPlusPlus14)
+ if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14)
Q.addConst();
// FIXME: Collect C++ address spaces.
// If there are multiple different address spaces, the source is invalid.
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index da39e2e..222c118 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1101,10 +1101,11 @@
return false;
}
-static void
-tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc,
- SourceLocation &ConstexprLoc,
- SourceLocation &DeclEndLoc) {
+static void tryConsumeLambdaSpecifierToken(Parser &P,
+ SourceLocation &MutableLoc,
+ SourceLocation &ConstexprLoc,
+ SourceLocation &ConstevalLoc,
+ SourceLocation &DeclEndLoc) {
assert(MutableLoc.isInvalid());
assert(ConstexprLoc.isInvalid());
// Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc
@@ -1132,6 +1133,15 @@
ConstexprLoc = P.ConsumeToken();
DeclEndLoc = ConstexprLoc;
break /*switch*/;
+ case tok::kw_consteval:
+ if (ConstevalLoc.isValid()) {
+ P.Diag(P.getCurToken().getLocation(),
+ diag::err_lambda_decl_specifier_repeated)
+ << 2 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
+ }
+ ConstevalLoc = P.ConsumeToken();
+ DeclEndLoc = ConstevalLoc;
+ break /*switch*/;
default:
return;
}
@@ -1147,12 +1157,25 @@
: diag::warn_cxx14_compat_constexpr_on_lambda);
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
- DS.SetConstexprSpec(ConstexprLoc, PrevSpec, DiagID);
+ DS.SetConstexprSpec(CSK_constexpr, ConstexprLoc, PrevSpec, DiagID);
assert(PrevSpec == nullptr && DiagID == 0 &&
"Constexpr cannot have been set previously!");
}
}
+static void addConstevalToLambdaDeclSpecifier(Parser &P,
+ SourceLocation ConstevalLoc,
+ DeclSpec &DS) {
+ if (ConstevalLoc.isValid()) {
+ P.Diag(ConstevalLoc, diag::warn_cxx20_compat_consteval);
+ const char *PrevSpec = nullptr;
+ unsigned DiagID = 0;
+ DS.SetConstexprSpec(CSK_consteval, ConstevalLoc, PrevSpec, DiagID);
+ if (DiagID != 0)
+ P.Diag(ConstevalLoc, DiagID) << PrevSpec;
+ }
+}
+
/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
@@ -1263,14 +1286,16 @@
// compatible with MSVC.
MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc);
- // Parse mutable-opt and/or constexpr-opt, and update the DeclEndLoc.
+ // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update the
+ // DeclEndLoc.
SourceLocation MutableLoc;
SourceLocation ConstexprLoc;
- tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc,
- DeclEndLoc);
+ SourceLocation ConstevalLoc;
+ tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
+ ConstevalLoc, DeclEndLoc);
addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
-
+ addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
// Parse exception-specification[opt].
ExceptionSpecificationType ESpecType = EST_None;
SourceRange ESpecRange;
@@ -1322,7 +1347,7 @@
TrailingReturnType),
std::move(Attr), DeclEndLoc);
} else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
- tok::kw_constexpr) ||
+ tok::kw_constexpr, tok::kw_consteval) ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
// It's common to forget that one needs '()' before 'mutable', an attribute
// specifier, or the result type. Deal with this.
@@ -1333,6 +1358,7 @@
case tok::kw___attribute:
case tok::l_square: TokKind = 2; break;
case tok::kw_constexpr: TokKind = 3; break;
+ case tok::kw_consteval: TokKind = 4; break;
default: llvm_unreachable("Unknown token kind");
}
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 13d43d5..a413f9a 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1221,6 +1221,7 @@
/// 'friend'
/// 'typedef'
/// [C++11] 'constexpr'
+/// [C++20] 'consteval'
/// [GNU] attributes declaration-specifiers[opt]
///
/// storage-class-specifier:
@@ -1406,6 +1407,7 @@
case tok::kw_friend:
case tok::kw_typedef:
case tok::kw_constexpr:
+ case tok::kw_consteval:
// storage-class-specifier
case tok::kw_register:
case tok::kw_static: