Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -1856,7 +1856,7 @@ 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; @@ -1886,29 +1886,24 @@ 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); @@ -2105,8 +2100,21 @@ } /// 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(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 Index: clang/include/clang/AST/DeclBase.h =================================================================== --- clang/include/clang/AST/DeclBase.h +++ clang/include/clang/AST/DeclBase.h @@ -1500,7 +1500,9 @@ 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 @@ }; /// 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 @@ /// 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. Index: clang/include/clang/AST/DeclCXX.h =================================================================== --- clang/include/clang/AST/DeclCXX.h +++ clang/include/clang/AST/DeclCXX.h @@ -2057,7 +2057,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -360,7 +360,7 @@ 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 @@ InGroup, 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">; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -704,7 +704,7 @@ "'main' is not allowed to be declared _Noreturn">, InGroup
; 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'">; @@ -1594,6 +1594,8 @@ "'mutable' can only be applied to member variables">; def err_virtual_in_union : Error< "unions cannot have virtual functions">; +def err_consteval_non_function : Error< + "'virtual' can only appear on functions and constructors">; def err_virtual_non_function : Error< "'virtual' can only appear on non-static member functions">; def err_virtual_out_of_class : Error< @@ -2312,14 +2314,17 @@ InGroup>; 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 +2334,8 @@ 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 +2350,12 @@ "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; @@ -2400,9 +2405,9 @@ "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, DefaultIgnore; @@ -7850,6 +7855,9 @@ 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 be constexpr">; def warn_defaulted_method_deleted : Warning< "explicitly defaulted %sub{select_special_member_kind}0 is implicitly " "deleted">, InGroup>; @@ -9419,7 +9427,7 @@ "'%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 before defining " "a coroutine">; @@ -9657,7 +9665,7 @@ "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< Index: clang/include/clang/Basic/Specifiers.h =================================================================== --- clang/include/clang/Basic/Specifiers.h +++ clang/include/clang/Basic/Specifiers.h @@ -28,6 +28,13 @@ 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, Index: clang/include/clang/Basic/TokenKinds.def =================================================================== --- clang/include/clang/Basic/TokenKinds.def +++ clang/include/clang/Basic/TokenKinds.def @@ -384,8 +384,9 @@ 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) Index: clang/include/clang/Sema/DeclSpec.h =================================================================== --- clang/include/clang/Sema/DeclSpec.h +++ clang/include/clang/Sema/DeclSpec.h @@ -363,7 +363,7 @@ unsigned Friend_specified : 1; // constexpr-specifier - unsigned Constexpr_specified : 1; + ConstexprSpecKind ConstexprSpecifier : 2; union { UnionParsedType TypeRep; @@ -433,7 +433,7 @@ 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 @@ 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 @@ 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 @@ 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(); } Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -5742,7 +5742,7 @@ startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, ArrayRef Params, - bool IsConstexprSpecified, + ConstexprSpecKind ConstexprKind, Optional> Mangling = None); /// Endow the lambda scope info with the relevant properties. Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -3092,7 +3092,7 @@ 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(D)) { @@ -3130,19 +3130,20 @@ 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(D)) { if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(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; } Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -2704,7 +2704,8 @@ 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), @@ -2724,7 +2725,7 @@ FunctionDeclBits.IsExplicitlyDefaulted = false; FunctionDeclBits.HasImplicitReturnZero = false; FunctionDeclBits.IsLateTemplateParsed = false; - FunctionDeclBits.IsConstexpr = isConstexprSpecified; + FunctionDeclBits.ConstexprKind = ConstexprKind; FunctionDeclBits.InstantiationIsPending = false; FunctionDeclBits.UsesSEHTry = false; FunctionDeclBits.HasSkippedBody = false; @@ -4521,13 +4522,12 @@ 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; } @@ -4535,7 +4535,7 @@ 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) { Index: clang/lib/AST/DeclCXX.cpp =================================================================== --- clang/lib/AST/DeclCXX.cpp +++ clang/lib/AST/DeclCXX.cpp @@ -767,7 +767,7 @@ // [...] has at least one constexpr constructor or constructor template // (possibly inherited from a base class) that is not a copy or move // constructor [...] - if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) + if ((Constructor->isConstexpr()) && !Constructor->isCopyOrMoveConstructor()) data().HasConstexprNonCopyMoveConstructor = true; } @@ -1995,22 +1995,22 @@ 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 @@ 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(Inherited)); setImplicit(isImplicitlyDeclared); @@ -2390,9 +2390,10 @@ unsigned Extra = additionalSizeToAlloc( 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 @@ 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 @@ 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::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 { Index: clang/lib/AST/DeclPrinter.cpp =================================================================== --- clang/lib/AST/DeclPrinter.cpp +++ clang/lib/AST/DeclPrinter.cpp @@ -610,7 +610,9 @@ 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); Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -4558,7 +4558,8 @@ } // Can we evaluate this function call? - if (Definition && Definition->isConstexpr() && Body) + if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl() && + Body) return true; if (Info.getLangOpts().CPlusPlus11) { @@ -4581,7 +4582,7 @@ << CD->getInheritedConstructor().getConstructor()->getParent(); else Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1) - << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; + << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; Info.Note(DiagDecl->getLocation(), diag::note_declared_at); } else { Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr); Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -255,9 +255,12 @@ if (D->isInvalidDecl()) OS << " invalid"; - if (const FunctionDecl *FD = dyn_cast(D)) - if (FD->isConstexpr()) + if (const FunctionDecl *FD = dyn_cast(D)) { + if (FD->isConstexprSpecified()) OS << " constexpr"; + if (FD->isConsteval()) + OS << " consteval"; + } if (!isa(*D)) { const auto *MD = dyn_cast(D); Index: clang/lib/Parse/ParseCXXInlineMethods.cpp =================================================================== --- clang/lib/Parse/ParseCXXInlineMethods.cpp +++ clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -109,7 +109,7 @@ // the tokens and store them for parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && D.getFunctionDefinitionKind() == FDK_Definition && - !D.getDeclSpec().isConstexprSpecified() && + !D.getDeclSpec().hasConstexprSpecifier() && !(FnD && FnD->getAsFunction() && FnD->getAsFunction()->getReturnType()->getContainedAutoType()) && ((Actions.CurContext->isDependentContext() || Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -2487,8 +2487,9 @@ } // Issue diagnostic and remove constexpr specifier if present. - if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) { - Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr); + if (DS.hasConstexprSpecifier() && DSC != DeclSpecContext::DSC_condition) { + Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr) + << (DS.getConstexprSpecifier() == CSK_consteval); DS.ClearConstexprSpec(); } } @@ -3626,7 +3627,12 @@ // constexpr case tok::kw_constexpr: - isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); + isInvalid = DS.SetConstexprSpec(CSK_constexpr, Loc, PrevSpec, DiagID); + break; + + // consteval + case tok::kw_consteval: + isInvalid = DS.SetConstexprSpec(CSK_consteval, Loc, PrevSpec, DiagID); break; // type-specifier @@ -5031,6 +5037,9 @@ case tok::annot_decltype: case tok::kw_constexpr: + // C++20 consteval. + case tok::kw_consteval: + // C11 _Atomic case tok::kw__Atomic: return true; @@ -6267,7 +6276,7 @@ Actions.CurContext->isRecord()); Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); - if (D.getDeclSpec().isConstexprSpecified() && !getLangOpts().CPlusPlus14) + if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14) Q.addConst(); // FIXME: Collect C++ address spaces. // If there are multiple different address spaces, the source is invalid. Index: clang/lib/Parse/ParseExprCXX.cpp =================================================================== --- clang/lib/Parse/ParseExprCXX.cpp +++ clang/lib/Parse/ParseExprCXX.cpp @@ -1101,10 +1101,11 @@ return false; } -static void -tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc, - SourceLocation &ConstexprLoc, - SourceLocation &DeclEndLoc) { +static void tryConsumeLambdaSpecifierToken(Parser &P, + SourceLocation &MutableLoc, + SourceLocation &ConstexprLoc, + SourceLocation &ConstevalLoc, + SourceLocation &DeclEndLoc) { assert(MutableLoc.isInvalid()); assert(ConstexprLoc.isInvalid()); // Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc @@ -1132,6 +1133,15 @@ ConstexprLoc = P.ConsumeToken(); DeclEndLoc = ConstexprLoc; break /*switch*/; + case tok::kw_consteval: + if (ConstevalLoc.isValid()) { + P.Diag(P.getCurToken().getLocation(), + diag::err_lambda_decl_specifier_repeated) + << 2 << FixItHint::CreateRemoval(P.getCurToken().getLocation()); + } + ConstevalLoc = P.ConsumeToken(); + DeclEndLoc = ConstevalLoc; + break /*switch*/; default: return; } @@ -1147,12 +1157,24 @@ : 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()) { + 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 +1285,16 @@ // compatible with MSVC. MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc); - // Parse mutable-opt and/or constexpr-opt, and update the DeclEndLoc. + // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update the + // DeclEndLoc. SourceLocation MutableLoc; SourceLocation ConstexprLoc; - tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc, - DeclEndLoc); + SourceLocation ConstevalLoc; + tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc, + ConstevalLoc, DeclEndLoc); addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); - + addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); // Parse exception-specification[opt]. ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; @@ -1322,7 +1346,7 @@ TrailingReturnType), std::move(Attr), DeclEndLoc); } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, - tok::kw_constexpr) || + tok::kw_constexpr, tok::kw_consteval) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { // It's common to forget that one needs '()' before 'mutable', an attribute // specifier, or the result type. Deal with this. @@ -1333,6 +1357,7 @@ case tok::kw___attribute: case tok::l_square: TokKind = 2; break; case tok::kw_constexpr: TokKind = 3; break; + case tok::kw_consteval: TokKind = 4; break; default: llvm_unreachable("Unknown token kind"); } Index: clang/lib/Parse/ParseTentative.cpp =================================================================== --- clang/lib/Parse/ParseTentative.cpp +++ clang/lib/Parse/ParseTentative.cpp @@ -1221,6 +1221,7 @@ /// 'friend' /// 'typedef' /// [C++11] 'constexpr' +/// [C++20] 'consteval' /// [GNU] attributes declaration-specifiers[opt] /// /// storage-class-specifier: @@ -1406,6 +1407,7 @@ case tok::kw_friend: case tok::kw_typedef: case tok::kw_constexpr: + case tok::kw_consteval: // storage-class-specifier case tok::kw_register: case tok::kw_static: Index: clang/lib/Sema/DeclSpec.cpp =================================================================== --- clang/lib/Sema/DeclSpec.cpp +++ clang/lib/Sema/DeclSpec.cpp @@ -564,6 +564,15 @@ 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 @@ 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,7 +1290,7 @@ 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 (hasConstexprSpecifier()) S.Diag(ConstexprLoc, diag::warn_cxx98_compat_constexpr); // C++ [class.friend]p6: Index: clang/lib/Sema/SemaCoroutine.cpp =================================================================== --- clang/lib/Sema/SemaCoroutine.cpp +++ clang/lib/Sema/SemaCoroutine.cpp @@ -210,6 +210,7 @@ DiagConstexpr, DiagAutoRet, DiagVarargs, + DiagConsteval, }; bool Diagnosed = false; auto DiagInvalid = [&](InvalidFuncDiag ID) { @@ -244,7 +245,7 @@ // 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()) Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -4292,14 +4292,18 @@ 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 @@ 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 @@ 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 @@ (!R->getAsAdjusted() && 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 @@ } 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 @@ return CXXConstructorDecl::Create( SemaRef.Context, cast(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 @@ 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 @@ IsVirtualOkay = true; return CXXConversionDecl::Create( SemaRef.Context, cast(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 @@ // This is a C++ method declaration. CXXMethodDecl *Ret = CXXMethodDecl::Create( SemaRef.Context, cast(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 @@ // - 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 @@ 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 @@ } } - 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 @@ // be either constructors or to return a literal type. Therefore, // destructors cannot be declared constexpr. if (isa(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 @@ DeletedFuncs = 5, DefaultedFuncs = 6, ConstexprFuncs = 7, + ConstevalFuncs = 8, }; enum Different { CallingConv = 0, @@ -9602,7 +9612,8 @@ 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(NewQType); @@ -9633,7 +9644,7 @@ 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 @@ } 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 @@ 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 @@ 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 Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -7460,12 +7460,10 @@ // 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()) Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -638,9 +638,9 @@ // 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 @@ 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 @@ 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(FD))) + SemaRef.RequireLiteralType( + ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1, + PD->getSourceRange(), isa(FD), + FD->isConsteval())) return false; } return true; @@ -1661,7 +1662,8 @@ 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 @@ default: SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt) - << isa(Dcl); + << isa(Dcl) << Dcl->isConsteval(); return false; } } @@ -1960,7 +1962,7 @@ } SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt) - << isa(Dcl); + << isa(Dcl) << Dcl->isConsteval(); return false; } @@ -2082,7 +2084,8 @@ 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 @@ 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 @@ : isa(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 @@ // 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 @@ // 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 *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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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(); Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -16811,13 +16811,11 @@ DeclRefExpr *DRE = dyn_cast(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()); Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -370,7 +370,7 @@ CXXMethodDecl *Sema::startLambdaDefinition( CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc, - ArrayRef Params, const bool IsConstexprSpecified, + ArrayRef Params, ConstexprSpecKind ConstexprKind, Optional> Mangling) { QualType MethodType = MethodTypeInfo->getType(); TemplateParameterList *TemplateParams = @@ -400,16 +400,12 @@ = 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 @@ CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params, - ParamInfo.getDeclSpec().isConstexprSpecified()); + ParamInfo.getDeclSpec().getConstexprSpecifier()); if (ExplicitParams) CheckCXXDefaultArguments(Method); @@ -1341,7 +1337,7 @@ 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 @@ 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 @@ 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 @@ !isa(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. Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -3693,7 +3693,8 @@ } 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*/; Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -1147,7 +1147,7 @@ // 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: @@ -8365,7 +8365,7 @@ // 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. @@ -9254,7 +9254,7 @@ 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(), Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1768,7 +1768,7 @@ 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()); } @@ -2076,7 +2076,7 @@ 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(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, @@ -2088,12 +2088,12 @@ 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()) Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -5146,7 +5146,7 @@ // 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(); } Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -11337,7 +11337,7 @@ Class, E->getIntroducerRange(), NewCallOpTSI, E->getCallOperator()->getEndLoc(), NewCallOpTSI->getTypeLoc().castAs().getParams(), - E->getCallOperator()->isConstexpr(), Mangling); + E->getCallOperator()->getConstexprKind(), Mangling); LSI->CallOperator = NewCallOperator; Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -868,7 +868,7 @@ FD->setDefaulted(Record.readInt()); FD->setExplicitlyDefaulted(Record.readInt()); FD->setHasImplicitReturnZero(Record.readInt()); - FD->setConstexpr(Record.readInt()); + FD->setConstexprKind(static_cast(Record.readInt())); FD->setUsesSEHTry(Record.readInt()); FD->setHasSkippedBody(Record.readInt()); FD->setIsMultiVersion(Record.readInt()); Index: clang/test/SemaCXX/cxx2a-compat.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-compat.cpp +++ clang/test/SemaCXX/cxx2a-compat.cpp @@ -56,4 +56,13 @@ #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 Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- /dev/null +++ clang/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; +}