[PATCH] D61790: [C++20] add consteval specifier
rsmith added a comment. Thanks for working on this! Comments on the general approach: - We should only evaluate each immediate invocation once (this will become essential once we start supporting reflection -- and particularly operations that mutate the AST -- inside `consteval` functions). - Each time an immediate invocation is formed, you should create a `ConstantExpr` AST node wrapping that call to reflect that it is a constant. - You should change `ConstantExpr` to store an `APValue` representing the evaluated value of the expression. Most of the above should be done as a separate preparatory change; we should be able to remove a lot of the existing ad-hoc caching of evaluated values (eg, for enumerators and the initializers of variables) at the same time. Please also split this into smaller pieces. If you split off a patch to just add the keyword, parsing, and AST representation for the `consteval` specifier (but treat it identically to `constexpr` for constant evaluation purposes), that'd be a good first patch for this feature. Comment at: clang/include/clang/AST/Decl.h:2102 /// Whether this is a (C++11) constexpr function or constexpr constructor. bool isConstexpr() const { return FunctionDeclBits.IsConstexpr; } void setConstexpr(bool IC) { FunctionDeclBits.IsConstexpr = IC; } Please rename this to `isConstexprSpecified()` (compare this to how we model `inline`, which has similar behavior: it can be explicit, or can be implied by other properties of the function). Comment at: clang/include/clang/AST/Decl.h:2109 + + bool isConstexprOrConsteval() const { return isConstexpr() || isConsteval(); } + Both the `constexpr` and `consteval` specifiers make a function a "constexpr function", so I think this should be called simply `isConstexpr`; callers that want to distinguish `constexpr` from `consteval` can use `isConsteval()` (or we can add a `getConstexprKind()` or similar function). Comment at: clang/include/clang/AST/DeclCXX.h:2115 +QualType T, TypeSourceInfo *TInfo, StorageClass SC, +bool isInline, bool isConstexpr, bool isConsteval, +SourceLocation EndLocation) Instead of the three bool flags in a row here (which will make call sites hard to read), consider using an enum, perhaps: ``` enum class ConstexprSpecifierKind { None, Constexpr, Consteval }; ``` Comment at: clang/include/clang/Basic/DiagnosticSemaKinds.td:2297-2300 +def err_consteval_cannot_be_constant_eval : Error< + "call to %0 cannot be constant evaluated">; +def note_argument_n_cannot_be_constant_eval : Note< + "argument %0 cannot be constant evaluated">; It would be useful in these diagnostics to explain why the call is required to be constant evaluated; please also use the standard terminology "constant expression" here. (Eg, "call to consteval function %0 is not a constant expression") Comment at: clang/include/clang/Basic/DiagnosticSemaKinds.td:2308-2314 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_dtor : Error<"destructor cannot be marked %0">; +def err_invalid_consteval_decl_kind : Error< + "operator %select{new|delete|new[]|delete[]}0 cannot be marked consteval">; +def err_take_adress_of_consteval_decl : Error< + "taking address of a %0">; In these diagnostics (including the existing one for tags), we should say "declared constexpr" not "marked constexpr". Comment at: clang/include/clang/Basic/TokenKinds.def:390-391 +// C++ consteval proposal +CXX2A_KEYWORD(consteval , 0) + This and `char8_t` are both adopted C++2a features now (they'e not just proposals any more); please change the comment to just "C++2a keywords". Comment at: clang/include/clang/Sema/DeclSpec.h:404 SourceLocation FS_forceinlineLoc; - SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; + SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConstevalLoc; SourceLocation TQ_pipeLoc; I think it would be preferable to track only one location here (for the `constexpr` / `consteval` specifier) and store a constexpr specifier kind instead of `Constexpr_specified`, like we do for the other kinds of specifier for which we allow only one of a set of keywords. Comment at: clang/include/clang/Sema/Sema.h:985-986 +/// cases in a switch statement). +/// - "immediate function context" in C++2a terms, a call to a function +/// marked as consteval ConstantEvaluated, An "immediate function context" is also "potentially evaluated"; I think what we want to say here is something like "The current
[PATCH] D61790: [C++20] add consteval specifier
efriedma added a comment. "complex" in this context is the C99 `_Complex`, which is supported in C++ as an extension, using the same syntax as C. You can just declare a variable with type `_Complex float`. If you need to manipulate the real and imaginary parts of a variable, you can use the gcc extension `__real__`/`__imag__`, although I don't think you need to. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D61790/new/ https://reviews.llvm.org/D61790 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D61790: [C++20] add consteval specifier
martong resigned from this revision. martong added a comment. Herald added a subscriber: rnkovacs. ASTImporter.cpp looks good to me. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D61790/new/ https://reviews.llvm.org/D61790 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D61790: [C++20] add consteval specifier
Tyker created this revision. Tyker added a reviewer: rsmith. Herald added a reviewer: martong. Herald added a reviewer: shafik. Herald added a project: clang. Herald added a subscriber: cfe-commits. this revision adds the consteval specifier as specified by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1073r3.html Changes: - add the consteval keyword. - add parsing of consteval specifier for normal declarations and lambdas expressions. - add the a bit to FunctionDeclBits for consteval. - adapt creation of FunctionDecl and some classes inheriting from it to take an extra bool for consteval. - change most calls to FunctionDecl::isConstexpr into call to FunctionDecl::isConstexprOrConsteval. - add semantic checking to prevent call to consteval function that cannot be constant evaluated. - add semantic checking to prevent taking address from consteval function. - add semantic checking to prevent consteval specified allocation function. - add tests for semantic. The code-gen has not yet been adapted, but it will need to be change to not emit consteval function and ensure calls to consteval function are folded correctly. Repository: rC Clang https://reviews.llvm.org/D61790 Files: clang/include/clang/AST/Decl.h clang/include/clang/AST/DeclBase.h clang/include/clang/AST/DeclCXX.h clang/include/clang/Basic/DiagnosticParseKinds.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/TokenKinds.def clang/include/clang/Sema/DeclSpec.h clang/include/clang/Sema/Sema.h clang/lib/AST/ASTImporter.cpp clang/lib/AST/Decl.cpp clang/lib/AST/DeclCXX.cpp clang/lib/AST/DeclPrinter.cpp clang/lib/AST/ExprConstant.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/Analysis/ReachableCode.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/ParseExprCXX.cpp clang/lib/Parse/ParseTentative.cpp clang/lib/Sema/DeclSpec.cpp clang/lib/Sema/Sema.cpp clang/lib/Sema/SemaCoroutine.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaLambda.cpp clang/lib/Sema/SemaOverload.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTWriterDecl.cpp clang/test/SemaCXX/cxx2a-compat.cpp clang/test/SemaCXX/cxx2a-consteval.cpp Index: clang/test/SemaCXX/cxx2a-consteval.cpp === --- /dev/null +++ clang/test/SemaCXX/cxx2a-consteval.cpp @@ -0,0 +1,224 @@ +// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify + +int i_global; // expected-note+ {{declared here}} +extern int i_extern; // expected-note+ {{declared here}} +const int i_const = 0; +constexpr int i_constexpr = 0; + +consteval int f_eval(int i) { +// expected-note@-1+ {{consteval function declared here}} + return i; +} + +constexpr auto l_eval = [](int i) consteval { +// expected-note@-1+ {{consteval operator declared here}} + return i; +}; + +constexpr int f_expr(int i) { + return i; +} + +struct A { + consteval int f_eval(int i) const { +// expected-note@-1+ {{consteval function declared here}} +return i; + } +}; + +constexpr A a; + +namespace invalid_call_args { + +int d0 = f_eval(0); +int l0 = l_eval(0); +int m0 = a.f_eval(0); +int d2 = f_eval(i_extern); +// expected-error@-1 {{call to consteval function cannot be constant evaluated}} +// expected-note@-2 {{argument 0 cannot be constant evaluated}} +// expected-note@-3 {{not allowed in a constant expression}} +int l2 = l_eval(i_extern); +// expected-error@-1 {{call to consteval operator cannot be constant evaluated}} +// expected-note@-2 {{argument 0 cannot be constant evaluated}} +// expected-note@-3 {{not allowed in a constant expression}} +int m2 = a.f_eval(i_extern); +// expected-error@-1 {{call to consteval function cannot be constant evaluated}} +// expected-note@-2 {{argument 0 cannot be constant evaluated}} +// expected-note@-3 {{not allowed in a constant expression}} +int d4 = f_eval(i_const); +int l4 = l_eval(i_const); +int m4 = a.f_eval(i_const); +int d6 = f_eval(i_constexpr); +int l6 = l_eval(i_constexpr); +int m6 = a.f_eval(i_constexpr); +int d8 = f_eval(i_global); +// expected-error@-1 {{call to consteval function cannot be constant evaluated}} +// expected-note@-2 {{argument 0 cannot be constant evaluated}} +// expected-note@-3 {{not allowed in a constant expression}} +int l8 = l_eval(i_global); +// expected-error@-1 {{call to consteval operator cannot be constant evaluated}} +// expected-note@-2 {{argument 0 cannot be constant evaluated}} +// expected-note@-3 {{not allowed in a constant expression}} +int m8 = a.f_eval(i_global); +// expected-error@-1 {{call to consteval function cannot be constant evaluated}} +// expected-note@-2 {{argument 0 cannot be constant evaluated}} +// expected-note@-3 {{not allowed in a constant expression}} +