[C++20] add Basic consteval specifier

Summary:
this revision adds Lexing, Parsing and Basic Semantic for the consteval specifier as specified by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1073r3.html

with this patch, the consteval specifier is treated as constexpr but can only be applied to function declaration.

Changes:
 - add the consteval keyword.
 - add parsing of consteval specifier for normal declarations and lambdas expressions.
 - add the whether a declaration is constexpr is now represented by and enum everywhere except for variable because they can't be consteval.
 - adapt diagnostic about constexpr to print constexpr or consteval depending on the case.
 - add tests for basic semantic.

Reviewers: rsmith, martong, shafik

Reviewed By: rsmith

Subscribers: eraman, efriedma, rnkovacs, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D61790

llvm-svn: 363362
This commit is contained in:
Gauthier Harnisch 2019-06-14 08:56:20 +00:00
parent b63e577444
commit 796ed03b84
37 changed files with 408 additions and 238 deletions

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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">;

View File

@ -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">;

View File

@ -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<

View File

@ -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,

View File

@ -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)

View File

@ -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();
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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) {

View File

@ -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 {

View File

@ -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);

View File

@ -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);

View File

@ -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() ||

View File

@ -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.

View File

@ -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");
}

View File

@ -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:

View File

@ -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.

View File

@ -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())

View File

@ -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

View File

@ -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())

View File

@ -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();

View File

@ -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());

View File

@ -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.

View File

@ -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*/;

View File

@ -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(),

View File

@ -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())

View File

@ -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();
}

View File

@ -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;

View File

@ -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());

View File

@ -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());

View File

@ -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

View File

@ -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;
}

View File

@ -2127,7 +2127,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
clang::FunctionDecl *func_decl = FunctionDecl::Create(
*ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type,
nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype,
isConstexprSpecified);
isConstexprSpecified ? CSK_constexpr : CSK_unspecified);
// We have to do more than just synthesize the FunctionDecl. We have to
// synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do

View File

@ -2170,7 +2170,7 @@ FunctionDecl *ClangASTContext::CreateFunctionDeclaration(
*ast, decl_ctx, SourceLocation(), SourceLocation(), declarationName,
ClangUtil::GetQualType(function_clang_type), nullptr,
(clang::StorageClass)storage, is_inline, hasWrittenPrototype,
isConstexprSpecified);
isConstexprSpecified ? CSK_constexpr : CSK_unspecified);
if (func_decl)
decl_ctx->addDecl(func_decl);
@ -8210,7 +8210,7 @@ clang::CXXMethodDecl *ClangASTContext::AddMethodToCXXRecordType(
clang::SourceLocation()),
method_qual_type,
nullptr, // TypeSourceInfo *
explicit_spec, is_inline, is_artificial, false /*is_constexpr*/);
explicit_spec, is_inline, is_artificial, CSK_unspecified);
cxx_method_decl = cxx_ctor_decl;
} else {
clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;
@ -8233,7 +8233,7 @@ clang::CXXMethodDecl *ClangASTContext::AddMethodToCXXRecordType(
clang::SourceLocation()),
method_qual_type,
nullptr, // TypeSourceInfo *
SC, is_inline, false /*is_constexpr*/, clang::SourceLocation());
SC, is_inline, CSK_unspecified, clang::SourceLocation());
} else if (num_params == 0) {
// Conversion operators don't take params...
cxx_method_decl = clang::CXXConversionDecl::Create(
@ -8245,7 +8245,7 @@ clang::CXXMethodDecl *ClangASTContext::AddMethodToCXXRecordType(
clang::SourceLocation()),
method_qual_type,
nullptr, // TypeSourceInfo *
is_inline, explicit_spec, false /*is_constexpr*/,
is_inline, explicit_spec, CSK_unspecified,
clang::SourceLocation());
}
}
@ -8256,7 +8256,7 @@ clang::CXXMethodDecl *ClangASTContext::AddMethodToCXXRecordType(
clang::DeclarationNameInfo(decl_name, clang::SourceLocation()),
method_qual_type,
nullptr, // TypeSourceInfo *
SC, is_inline, false /*is_constexpr*/, clang::SourceLocation());
SC, is_inline, CSK_unspecified, clang::SourceLocation());
}
}