Skip to content

Commit

Permalink
[C++20] add Basic consteval specifier
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Ralender committed Jun 14, 2019
1 parent b63e577 commit 796ed03
Show file tree
Hide file tree
Showing 37 changed files with 408 additions and 238 deletions.
48 changes: 28 additions & 20 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1861,7 +1861,7 @@ class FunctionDecl : public DeclaratorDecl,
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>;

Expand Down Expand Up @@ -1891,29 +1891,24 @@ class FunctionDecl : public DeclaratorDecl,
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);

Expand Down Expand Up @@ -2110,8 +2105,21 @@ class FunctionDecl : public DeclaratorDecl,
}

/// 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
Expand Down
8 changes: 5 additions & 3 deletions clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down
41 changes: 19 additions & 22 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -2057,7 +2057,7 @@ class CXXDeductionGuideDecl : public FunctionDecl {
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);
Expand Down Expand Up @@ -2112,23 +2112,21 @@ 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);
}

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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2628,7 +2626,7 @@ class CXXConstructorDecl final
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() {
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;

Expand All @@ -2907,7 +2904,7 @@ class CXXConversionDecl : public CXXMethodDecl {
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);

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;

Expand Down Expand Up @@ -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">;
Expand Down
36 changes: 21 additions & 15 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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'">;
Expand Down Expand Up @@ -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<
Expand All @@ -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 "
Expand All @@ -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>;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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">>;
Expand Down Expand Up @@ -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">;
Expand Down Expand Up @@ -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<
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Specifiers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 796ed03

Please sign in to comment.