summaryrefslogtreecommitdiff
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
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
-rw-r--r--include/clang/AST/Decl.h48
-rw-r--r--include/clang/AST/DeclBase.h8
-rw-r--r--include/clang/AST/DeclCXX.h41
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td36
-rw-r--r--include/clang/Basic/Specifiers.h7
-rw-r--r--include/clang/Basic/TokenKinds.def3
-rw-r--r--include/clang/Sema/DeclSpec.h16
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--lib/AST/ASTImporter.cpp15
-rw-r--r--lib/AST/Decl.cpp14
-rw-r--r--lib/AST/DeclCXX.cpp50
-rw-r--r--lib/AST/DeclPrinter.cpp4
-rw-r--r--lib/AST/TextNodeDumper.cpp7
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp2
-rw-r--r--lib/Parse/ParseDecl.cpp17
-rw-r--r--lib/Parse/ParseExprCXX.cpp46
-rw-r--r--lib/Parse/ParseTentative.cpp2
-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
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp2
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp2
-rw-r--r--test/SemaCXX/cxx2a-compat.cpp9
-rw-r--r--test/SemaCXX/cxx2a-consteval.cpp58
35 files changed, 402 insertions, 232 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 37b6181c4e..f289cc431d 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1861,7 +1861,7 @@ protected:
FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified,
- bool isConstexprSpecified);
+ ConstexprSpecKind ConstexprKind);
using redeclarable_base = Redeclarable<FunctionDecl>;
@@ -1891,29 +1891,24 @@ public:
using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
- static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation StartLoc, SourceLocation NLoc,
- DeclarationName N, QualType T,
- TypeSourceInfo *TInfo,
- StorageClass SC,
- bool isInlineSpecified = false,
- bool hasWrittenPrototype = true,
- bool isConstexprSpecified = false) {
+ static FunctionDecl *
+ Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation NLoc, DeclarationName N, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC, bool isInlineSpecified = false,
+ bool hasWrittenPrototype = true,
+ ConstexprSpecKind ConstexprKind = CSK_unspecified) {
DeclarationNameInfo NameInfo(N, NLoc);
- return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo,
- SC,
+ return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC,
isInlineSpecified, hasWrittenPrototype,
- isConstexprSpecified);
+ ConstexprKind);
}
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- StorageClass SC,
- bool isInlineSpecified,
- bool hasWrittenPrototype,
- bool isConstexprSpecified = false);
+ const DeclarationNameInfo &NameInfo, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC,
+ bool isInlineSpecified, bool hasWrittenPrototype,
+ ConstexprSpecKind ConstexprKind);
static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2110,8 +2105,21 @@ public:
}
/// Whether this is a (C++11) constexpr function or constexpr constructor.
- bool isConstexpr() const { return FunctionDeclBits.IsConstexpr; }
- void setConstexpr(bool IC) { FunctionDeclBits.IsConstexpr = IC; }
+ bool isConstexpr() const {
+ return FunctionDeclBits.ConstexprKind != CSK_unspecified;
+ }
+ void setConstexprKind(ConstexprSpecKind CSK) {
+ FunctionDeclBits.ConstexprKind = CSK;
+ }
+ ConstexprSpecKind getConstexprKind() const {
+ return static_cast<ConstexprSpecKind>(FunctionDeclBits.ConstexprKind);
+ }
+ bool isConstexprSpecified() const {
+ return FunctionDeclBits.ConstexprKind == CSK_constexpr;
+ }
+ bool isConsteval() const {
+ return FunctionDeclBits.ConstexprKind == CSK_consteval;
+ }
/// Whether the instantiation of this function is pending.
/// This bit is set when the decision to instantiate this function is made
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index cebf2973c8..26edb7790c 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -1500,7 +1500,9 @@ class DeclContext {
uint64_t IsExplicitlyDefaulted : 1;
uint64_t HasImplicitReturnZero : 1;
uint64_t IsLateTemplateParsed : 1;
- uint64_t IsConstexpr : 1;
+
+ /// Kind of contexpr specifier as defined by ConstexprSpecKind.
+ uint64_t ConstexprKind : 2;
uint64_t InstantiationIsPending : 1;
/// Indicates if the function uses __try.
@@ -1528,7 +1530,7 @@ class DeclContext {
};
/// Number of non-inherited bits in FunctionDeclBitfields.
- enum { NumFunctionDeclBits = 24 };
+ enum { NumFunctionDeclBits = 25 };
/// Stores the bits used by CXXConstructorDecl. If modified
/// NumCXXConstructorDeclBits and the accessor
@@ -1545,7 +1547,7 @@ class DeclContext {
/// exactly 64 bits and thus the width of NumCtorInitializers
/// will need to be shrunk if some bit is added to NumDeclContextBitfields,
/// NumFunctionDeclBitfields or CXXConstructorDeclBitfields.
- uint64_t NumCtorInitializers : 24;
+ uint64_t NumCtorInitializers : 23;
uint64_t IsInheritingConstructor : 1;
/// Whether this constructor has a trail-allocated explicit specifier.
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 1f879c53f4..6133d2fce7 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -2057,7 +2057,7 @@ private:
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation)
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
- SC_None, false, false),
+ SC_None, false, CSK_unspecified),
ExplicitSpec(ES) {
if (EndLocation.isValid())
setRangeEnd(EndLocation);
@@ -2112,11 +2112,11 @@ class CXXMethodDecl : public FunctionDecl {
protected:
CXXMethodDecl(Kind DK, ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc, const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- StorageClass SC, bool isInline,
- bool isConstexpr, SourceLocation EndLocation)
- : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo,
- SC, isInline, isConstexpr) {
+ QualType T, TypeSourceInfo *TInfo, StorageClass SC,
+ bool isInline, ConstexprSpecKind ConstexprKind,
+ SourceLocation EndLocation)
+ : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, isInline,
+ ConstexprKind) {
if (EndLocation.isValid())
setRangeEnd(EndLocation);
}
@@ -2124,11 +2124,9 @@ protected:
public:
static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- StorageClass SC,
- bool isInline,
- bool isConstexpr,
+ const DeclarationNameInfo &NameInfo, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC,
+ bool isInline, ConstexprSpecKind ConstexprKind,
SourceLocation EndLocation);
static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2575,7 +2573,7 @@ class CXXConstructorDecl final
CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, ExplicitSpecifier ES, bool isInline,
- bool isImplicitlyDeclared, bool isConstexpr,
+ bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
InheritedConstructor Inherited);
void anchor() override;
@@ -2628,7 +2626,7 @@ public:
Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
- bool isConstexpr,
+ ConstexprSpecKind ConstexprKind,
InheritedConstructor Inherited = InheritedConstructor());
ExplicitSpecifier getExplicitSpecifier() {
@@ -2834,12 +2832,11 @@ class CXXDestructorDecl : public CXXMethodDecl {
Expr *OperatorDeleteThisArg = nullptr;
CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isImplicitlyDeclared)
- : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, /*isConstexpr=*/false, SourceLocation())
- {
+ const DeclarationNameInfo &NameInfo, QualType T,
+ TypeSourceInfo *TInfo, bool isInline,
+ bool isImplicitlyDeclared)
+ : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
+ SC_None, isInline, CSK_unspecified, SourceLocation()) {
setImplicit(isImplicitlyDeclared);
}
@@ -2890,9 +2887,9 @@ class CXXConversionDecl : public CXXMethodDecl {
CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, bool isInline, ExplicitSpecifier ES,
- bool isConstexpr, SourceLocation EndLocation)
+ ConstexprSpecKind ConstexprKind, SourceLocation EndLocation)
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, isConstexpr, EndLocation),
+ SC_None, isInline, ConstexprKind, EndLocation),
ExplicitSpec(ES) {}
void anchor() override;
@@ -2907,7 +2904,7 @@ public:
static CXXConversionDecl *
Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
- bool isInline, ExplicitSpecifier ES, bool isConstexpr,
+ bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
SourceLocation EndLocation);
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 06ef3263c6..52ab4b8ad3 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -172,6 +172,9 @@ def ext_cxx11_longlong : Extension<
def warn_cxx98_compat_longlong : Warning<
"'long long' is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
+def warn_cxx20_compat_consteval : Warning<
+ "consteval is incompatible with C++ standards before C++20">,
+ InGroup<CXX2aCompat>, DefaultIgnore;
def err_integer_literal_too_large : Error<
"integer literal is too large to be represented in any %select{signed |}0"
"integer type">;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 15a5ecf177..2cafbfc930 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -360,7 +360,7 @@ def err_typename_invalid_storageclass : Error<
def err_typename_invalid_functionspec : Error<
"type name does not allow function specifier to be specified">;
def err_typename_invalid_constexpr : Error<
- "type name does not allow constexpr specifier to be specified">;
+ "type name does not allow %select{constexpr|consteval}0 specifier to be specified">;
def err_typename_identifiers_only : Error<
"typename is allowed for identifiers only">;
@@ -875,9 +875,9 @@ def warn_cxx98_compat_lambda : Warning<
InGroup<CXX98Compat>, DefaultIgnore;
def err_lambda_missing_parens : Error<
"lambda requires '()' before %select{'mutable'|return type|"
- "attribute specifier|'constexpr'}0">;
+ "attribute specifier|'constexpr'|'consteval'}0">;
def err_lambda_decl_specifier_repeated : Error<
- "%select{'mutable'|'constexpr'}0 cannot appear multiple times in a lambda declarator">;
+ "%select{'mutable'|'constexpr'|'consteval'}0 cannot appear multiple times in a lambda declarator">;
def err_lambda_capture_misplaced_ellipsis : Error<
"ellipsis in pack %select{|init-}0capture must appear %select{after|before}0 "
"the name of the capture">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 37eed39fe5..5b4e18673f 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -704,7 +704,7 @@ def ext_noreturn_main : ExtWarn<
"'main' is not allowed to be declared _Noreturn">, InGroup<Main>;
def note_main_remove_noreturn : Note<"remove '_Noreturn'">;
def err_constexpr_main : Error<
- "'main' is not allowed to be declared constexpr">;
+ "'main' is not allowed to be declared %select{constexpr|consteval}0">;
def err_deleted_main : Error<"'main' is not allowed to be deleted">;
def err_mainlike_template_decl : Error<"%0 cannot be a template">;
def err_main_returns_nonint : Error<"'main' must return 'int'">;
@@ -2312,14 +2312,17 @@ def warn_cxx14_compat_constexpr_not_const : Warning<
InGroup<DiagGroup<"constexpr-not-const">>;
def err_invalid_constexpr : Error<
"%select{function parameter|typedef|non-static data member}0 "
- "cannot be constexpr">;
+ "cannot be %select{constexpr|consteval}1">;
def err_invalid_constexpr_member : Error<"non-static data member cannot be "
"constexpr%select{; did you intend to make it %select{const|static}0?|}1">;
def err_constexpr_tag : Error<
- "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">;
-def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
-def err_constexpr_no_declarators : Error<
- "constexpr can only be used in variable and function declarations">;
+ "%select{class|struct|interface|union|enum}0 "
+ "cannot be marked %select{constexpr|consteval}1">;
+def err_constexpr_dtor : Error<
+ "destructor cannot be marked %select{constexpr|consteval}0">;
+def err_constexpr_wrong_decl_kind : Error<
+ "%select{constexpr|consteval}0 can only be used "
+ "in %select{variable and |}0function declarations">;
def err_invalid_constexpr_var_decl : Error<
"constexpr variable declaration must be a definition">;
def err_constexpr_static_mem_var_requires_init : Error<
@@ -2329,8 +2332,8 @@ def err_constexpr_var_non_literal : Error<
def err_constexpr_var_requires_const_init : Error<
"constexpr variable %0 must be initialized by a constant expression">;
def err_constexpr_redecl_mismatch : Error<
- "%select{non-constexpr declaration of %0 follows constexpr declaration"
- "|constexpr declaration of %0 follows non-constexpr declaration}1">;
+ "%select{non-constexpr|constexpr|consteval}1 declaration of %0"
+ " follows %select{non-constexpr|constexpr|consteval}2 declaration">;
def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
def warn_cxx17_compat_constexpr_virtual : Warning<
"virtual constexpr functions are incompatible with "
@@ -2345,12 +2348,12 @@ def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 "
"with virtual base %plural{1:class|:classes}1 is not a literal type">;
def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
def err_constexpr_non_literal_return : Error<
- "constexpr function's return type %0 is not a literal type">;
+ "%select{constexpr|consteval}0 function's return type %1 is not a literal type">;
def err_constexpr_non_literal_param : Error<
- "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is "
+ "%select{constexpr|consteval}2 %select{function|constructor}1's %ordinal0 parameter type %3 is "
"not a literal type">;
def err_constexpr_body_invalid_stmt : Error<
- "statement not allowed in constexpr %select{function|constructor}0">;
+ "statement not allowed in %select{constexpr|consteval}1 %select{function|constructor}0">;
def ext_constexpr_body_invalid_stmt : ExtWarn<
"use of this statement in a constexpr %select{function|constructor}0 "
"is a C++14 extension">, InGroup<CXX14>;
@@ -2400,9 +2403,9 @@ def err_diagnose_if_invalid_diagnostic_type : Error<
"invalid diagnostic type for 'diagnose_if'; use \"error\" or \"warning\" "
"instead">;
def err_constexpr_body_no_return : Error<
- "no return statement in constexpr function">;
+ "no return statement in %select{constexpr|consteval}0 function">;
def err_constexpr_return_missing_expr : Error<
- "non-void constexpr function %0 should return a value">;
+ "non-void %select{constexpr|consteval}1 function %0 should return a value">;
def warn_cxx11_compat_constexpr_body_no_return : Warning<
"constexpr function with no return statements is incompatible with C++ "
"standards before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
@@ -7853,6 +7856,9 @@ def err_defaulted_copy_assign_not_ref : Error<
def err_incorrect_defaulted_constexpr : Error<
"defaulted definition of %sub{select_special_member_kind}0 "
"is not constexpr">;
+def err_incorrect_defaulted_consteval : Error<
+ "defaulted declaration of %sub{select_special_member_kind}0 "
+ "cannot be consteval because implicit definition is not constexpr">;
def warn_defaulted_method_deleted : Warning<
"explicitly defaulted %sub{select_special_member_kind}0 is implicitly "
"deleted">, InGroup<DiagGroup<"defaulted-function-deleted">>;
@@ -9422,7 +9428,7 @@ def err_coroutine_invalid_func_context : Error<
"'%1' cannot be used in %select{a constructor|a destructor"
"|a copy assignment operator|a move assignment operator|the 'main' function"
"|a constexpr function|a function with a deduced return type"
- "|a varargs function}0">;
+ "|a varargs function|a consteval function}0">;
def err_implied_coroutine_type_not_found : Error<
"%0 type was not found; include <experimental/coroutine> before defining "
"a coroutine">;
@@ -9660,7 +9666,7 @@ def err_multiversion_doesnt_support : Error<
"attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioned functions do not "
"yet support %select{function templates|virtual functions|"
"deduced return types|constructors|destructors|deleted functions|"
- "defaulted functions|constexpr functions}1">;
+ "defaulted functions|constexpr functions|consteval function}1">;
def err_multiversion_not_allowed_on_main : Error<
"'main' cannot be a multiversioned function">;
def err_multiversion_not_supported : Error<
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index be79311785..d1236e798e 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -28,6 +28,13 @@ namespace clang {
Unresolved,
};
+ /// Define the kind of constexpr specifier.
+ enum ConstexprSpecKind {
+ CSK_unspecified,
+ CSK_constexpr,
+ CSK_consteval
+ };
+
/// Specifies the width of a type, e.g., short, long, or long long.
enum TypeSpecifierWidth {
TSW_unspecified,
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 65f2c5d982..b185923359 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -384,8 +384,9 @@ COROUTINES_KEYWORD(co_yield)
MODULES_KEYWORD(module)
MODULES_KEYWORD(import)
-// C++ char8_t proposal
+// C++20 keywords.
CXX2A_KEYWORD(char8_t , CHAR8SUPPORT)
+CXX2A_KEYWORD(consteval , 0)
// C11 Extension
KEYWORD(_Float16 , KEYALL)
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index f1c2a67400..5c549d76aa 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -363,7 +363,7 @@ private:
unsigned Friend_specified : 1;
// constexpr-specifier
- unsigned Constexpr_specified : 1;
+ ConstexprSpecKind ConstexprSpecifier : 2;
union {
UnionParsedType TypeRep;
@@ -433,7 +433,7 @@ public:
TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified),
FS_inline_specified(false), FS_forceinline_specified(false),
FS_virtual_specified(false), FS_noreturn_specified(false),
- Friend_specified(false), Constexpr_specified(false),
+ Friend_specified(false), ConstexprSpecifier(CSK_unspecified),
FS_explicit_specifier(), Attrs(attrFactory), writtenBS(),
ObjCQualifiers(nullptr) {}
@@ -530,6 +530,7 @@ public:
static const char *getSpecifierName(DeclSpec::TSW W);
static const char *getSpecifierName(DeclSpec::SCS S);
static const char *getSpecifierName(DeclSpec::TSCS S);
+ static const char *getSpecifierName(ConstexprSpecKind C);
// type-qualifiers
@@ -718,8 +719,8 @@ public:
unsigned &DiagID);
bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
- bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID);
+ bool SetConstexprSpec(ConstexprSpecKind ConstexprKind, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID);
bool isFriendSpecified() const { return Friend_specified; }
SourceLocation getFriendSpecLoc() const { return FriendLoc; }
@@ -727,11 +728,14 @@ public:
bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); }
SourceLocation getModulePrivateSpecLoc() const { return ModulePrivateLoc; }
- bool isConstexprSpecified() const { return Constexpr_specified; }
+ ConstexprSpecKind getConstexprSpecifier() const { return ConstexprSpecifier; }
SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
+ bool hasConstexprSpecifier() const {
+ return ConstexprSpecifier != CSK_unspecified;
+ }
void ClearConstexprSpec() {
- Constexpr_specified = false;
+ ConstexprSpecifier = CSK_unspecified;
ConstexprLoc = SourceLocation();
}
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 584472a067..b34f5c9196 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -5746,7 +5746,7 @@ public:
startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange,
TypeSourceInfo *MethodType, SourceLocation EndLoc,
ArrayRef<ParmVarDecl *> Params,
- bool IsConstexprSpecified,
+ ConstexprSpecKind ConstexprKind,
Optional<std::pair<unsigned, Decl *>> Mangling = None);
/// Endow the lambda scope info with the relevant properties.
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 14bccd7711..b43491d061 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -3093,7 +3093,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ExplicitSpecifier(
ExplicitExpr,
FromConstructor->getExplicitSpecifier().getKind()),
- D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
+ D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind()))
return ToFunction;
} else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
@@ -3131,19 +3131,20 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
ExplicitSpecifier(ExplicitExpr,
FromConversion->getExplicitSpecifier().getKind()),
- D->isConstexpr(), SourceLocation()))
+ D->getConstexprKind(), SourceLocation()))
return ToFunction;
} else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
if (GetImportedOrCreateDecl<CXXMethodDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(),
- Method->isInlineSpecified(), D->isConstexpr(), SourceLocation()))
+ Method->isInlineSpecified(), D->getConstexprKind(),
+ SourceLocation()))
return ToFunction;
} else {
- if (GetImportedOrCreateDecl(ToFunction, D, Importer.getToContext(), DC,
- ToInnerLocStart, NameInfo, T, TInfo,
- D->getStorageClass(), D->isInlineSpecified(),
- D->hasWrittenPrototype(), D->isConstexpr()))
+ if (GetImportedOrCreateDecl(
+ ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
+ NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(),
+ D->hasWrittenPrototype(), D->getConstexprKind()))
return ToFunction;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 1b744c82a0..aeb7963f90 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2724,7 +2724,8 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
- bool isInlineSpecified, bool isConstexprSpecified)
+ bool isInlineSpecified,
+ ConstexprSpecKind ConstexprKind)
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
StartLoc),
DeclContext(DK), redeclarable_base(C), ODRHash(0),
@@ -2744,7 +2745,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.IsExplicitlyDefaulted = false;
FunctionDeclBits.HasImplicitReturnZero = false;
FunctionDeclBits.IsLateTemplateParsed = false;
- FunctionDeclBits.IsConstexpr = isConstexprSpecified;
+ FunctionDeclBits.ConstexprKind = ConstexprKind;
FunctionDeclBits.InstantiationIsPending = false;
FunctionDeclBits.UsesSEHTry = false;
FunctionDeclBits.HasSkippedBody = false;
@@ -4541,13 +4542,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass SC,
- bool isInlineSpecified,
+ StorageClass SC, bool isInlineSpecified,
bool hasWrittenPrototype,
- bool isConstexprSpecified) {
+ ConstexprSpecKind ConstexprKind) {
FunctionDecl *New =
new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo,
- SC, isInlineSpecified, isConstexprSpecified);
+ SC, isInlineSpecified, ConstexprKind);
New->setHasWrittenPrototype(hasWrittenPrototype);
return New;
}
@@ -4555,7 +4555,7 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(),
DeclarationNameInfo(), QualType(), nullptr,
- SC_None, false, false);
+ SC_None, false, CSK_unspecified);
}
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 941fd66c7b..48965966f0 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1995,22 +1995,22 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
return nullptr;
}
-CXXMethodDecl *
-CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- StorageClass SC, bool isInline,
- bool isConstexpr, SourceLocation EndLocation) {
- return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo,
- T, TInfo, SC, isInline, isConstexpr,
- EndLocation);
+CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo,
+ QualType T, TypeSourceInfo *TInfo,
+ StorageClass SC, bool isInline,
+ ConstexprSpecKind ConstexprKind,
+ SourceLocation EndLocation) {
+ return new (C, RD)
+ CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC,
+ isInline, ConstexprKind, EndLocation);
}
CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(),
- DeclarationNameInfo(), QualType(), nullptr,
- SC_None, false, false, SourceLocation());
+ return new (C, ID) CXXMethodDecl(
+ CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(),
+ QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation());
}
CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@@ -2367,9 +2367,9 @@ CXXConstructorDecl::CXXConstructorDecl(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
- bool isConstexpr, InheritedConstructor Inherited)
+ ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited)
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, isConstexpr, SourceLocation()) {
+ SC_None, isInline, ConstexprKind, SourceLocation()) {
setNumCtorInitializers(0);
setInheritingConstructor(static_cast<bool>(Inherited));
setImplicit(isImplicitlyDeclared);
@@ -2390,9 +2390,10 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
unsigned Extra =
additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
isInheritingConstructor, hasTraillingExplicit);
- auto *Result = new (C, ID, Extra) CXXConstructorDecl(
- C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
- ExplicitSpecifier(), false, false, false, InheritedConstructor());
+ auto *Result = new (C, ID, Extra)
+ CXXConstructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
+ QualType(), nullptr, ExplicitSpecifier(), false, false,
+ CSK_unspecified, InheritedConstructor());
Result->setInheritingConstructor(isInheritingConstructor);
Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
hasTraillingExplicit;
@@ -2404,7 +2405,7 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
- bool isConstexpr, InheritedConstructor Inherited) {
+ ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
@@ -2413,7 +2414,7 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
return new (C, RD, Extra)
CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline,
- isImplicitlyDeclared, isConstexpr, Inherited);
+ isImplicitlyDeclared, ConstexprKind, Inherited);
}
CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2566,19 +2567,20 @@ CXXConversionDecl *
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) CXXConversionDecl(
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
- false, ExplicitSpecifier(), false, SourceLocation());
+ false, ExplicitSpecifier(), CSK_unspecified, SourceLocation());
}
CXXConversionDecl *CXXConversionDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
- bool isInline, ExplicitSpecifier ES, bool isConstexpr,
+ bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
SourceLocation EndLocation) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
- return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo,
- isInline, ES, isConstexpr, EndLocation);
+ return new (C, RD)
+ CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES,
+ ConstexprKind, EndLocation);
}
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 78a7afdbf0..65532ec496 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -610,7 +610,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isInlineSpecified()) Out << "inline ";
if (D->isVirtualAsWritten()) Out << "virtual ";
if (D->isModulePrivate()) Out << "__module_private__ ";
- if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
+ if (D->isConstexprSpecified() && !D->isExplicitlyDefaulted())
+ Out << "constexpr ";
+ if (D->isConsteval()) Out << "consteval ";
ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D);
if (ExplicitSpec.isSpecified())
printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation);
diff --git a/lib/AST/TextNodeDumper.cpp b/lib/AST/TextNodeDumper.cpp
index 06388c28d9..1998cfaec0 100644
--- a/lib/AST/TextNodeDumper.cpp
+++ b/lib/AST/TextNodeDumper.cpp
@@ -255,9 +255,12 @@ void TextNodeDumper::Visit(const Decl *D) {
if (D->isInvalidDecl())
OS << " invalid";
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isConstexpr())
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isConstexprSpecified())
OS << " constexpr";
+ if (FD->isConsteval())
+ OS << " consteval";
+ }
if (!isa<FunctionDecl>(*D)) {
const auto *MD = dyn_cast<ObjCMethodDecl>(D);
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index f2e552a3ce..14151efd3d 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -109,7 +109,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
// 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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5589297953..2c9045d74a 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2487,8 +2487,9 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
}
// 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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// 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 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
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 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
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/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index da39e2e223..222c118262 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -1101,10 +1101,11 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
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 @@ tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc,
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 @@ addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc,
: 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 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// 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 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
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 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
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/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 13d43d5e68..a413f9a941 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -1221,6 +1221,7 @@ public:
/// 'friend'
/// 'typedef'
/// [C++11] 'constexpr'
+/// [C++20] 'consteval'
/// [GNU] attributes declaration-specifiers[opt]
///
/// storage-class-specifier:
@@ -1406,6 +1407,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
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:
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;
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 5d40b85b03..359c86d019 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -868,7 +868,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setDefaulted(Record.readInt());
FD->setExplicitlyDefaulted(Record.readInt());
FD->setHasImplicitReturnZero(Record.readInt());
- FD->setConstexpr(Record.readInt());
+ FD->setConstexprKind(static_cast<ConstexprSpecKind>(Record.readInt()));
FD->setUsesSEHTry(Record.readInt());
FD->setHasSkippedBody(Record.readInt());
FD->setIsMultiVersion(Record.readInt());
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 958957a70b..eb709f59c9 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -545,7 +545,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->isDefaulted());
Record.push_back(D->isExplicitlyDefaulted());
Record.push_back(D->hasImplicitReturnZero());
- Record.push_back(D->isConstexpr());
+ Record.push_back(D->getConstexprKind());
Record.push_back(D->usesSEHTry());
Record.push_back(D->hasSkippedBody());
Record.push_back(D->isMultiVersion());
diff --git a/test/SemaCXX/cxx2a-compat.cpp b/test/SemaCXX/cxx2a-compat.cpp
index 49db0bc539..c8d22b7310 100644
--- a/test/SemaCXX/cxx2a-compat.cpp
+++ b/test/SemaCXX/cxx2a-compat.cpp
@@ -56,4 +56,13 @@ struct C {
#if !defined(__cpp_conditional_explicit) || __cpp_conditional_explicit != 201806L
#error "the feature test macro __cpp_conditional_explicit isn't correct"
#endif
+#endif
+
+auto l = []() consteval {};
+int consteval();
+#if __cplusplus <= 201703L
+// expected-warning@-3 {{'consteval' is a keyword in C++2a}}
+// expected-error@-4 {{expected body of lambda expression}}
+#else
+// expected-error@-5 {{expected unqualified-id}}
#endif \ No newline at end of file
diff --git a/test/SemaCXX/cxx2a-consteval.cpp b/test/SemaCXX/cxx2a-consteval.cpp
new file mode 100644
index 0000000000..c531b92033
--- /dev/null
+++ b/test/SemaCXX/cxx2a-consteval.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify
+
+namespace basic_sema {
+
+consteval int f1(int i) {
+ return i;
+}
+
+consteval constexpr int f2(int i) {
+ //expected-error@-1 {{cannot combine}}
+ return i;
+}
+
+constexpr auto l_eval = [](int i) consteval {
+
+ return i;
+};
+
+constexpr consteval int f3(int i) {
+ //expected-error@-1 {{cannot combine}}
+ return i;
+}
+
+struct A {
+ consteval int f1(int i) const {
+ return i;
+ }
+ consteval A(int i);
+ consteval A() = default;
+ consteval ~A() = default; // expected-error {{destructor cannot be marked consteval}}
+};
+
+consteval struct B {}; // expected-error {{struct cannot be marked consteval}}
+
+consteval typedef B b; // expected-error {{typedef cannot be consteval}}
+
+consteval int redecl() {return 0;} // expected-note {{previous declaration is here}}
+constexpr int redecl() {return 0;} // expected-error {{constexpr declaration of 'redecl' follows consteval declaration}}
+
+consteval int i = 0; // expected-error {{consteval can only be used in function declarations}}
+
+consteval int; // expected-error {{consteval can only be used in function declarations}}
+
+consteval int f1() {} // expected-error {{no return statement in consteval function}}
+
+struct C {
+ C() {}
+};
+
+struct D {
+ C c;
+ consteval D() = default; // expected-error {{cannot be consteval}}
+};
+}
+
+consteval int main() { // expected-error {{'main' is not allowed to be declared consteval}}
+ return 0;
+}