+2019-11-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/88335 - Implement P1073R3: Immediate functions
+ * c-common.h (enum rid): Add RID_CONSTEVAL.
+ * c-common.c (c_common_reswords): Add consteval.
+
2019-10-30 Nathan Sidwell <nathan@acm.org>
* c-cppbuiltin.c (c_cpp_builtins): Add 'L' suffix to feature
{ "char32_t", RID_CHAR32, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "class", RID_CLASS, D_CXX_OBJC | D_CXXWARN },
{ "const", RID_CONST, 0 },
+ { "consteval", RID_CONSTEVAL, D_CXXONLY | D_CXX20 | D_CXXWARN },
{ "constexpr", RID_CONSTEXPR, D_CXXONLY | D_CXX11 | D_CXXWARN },
{ "constinit", RID_CONSTINIT, D_CXXONLY | D_CXX20 | D_CXXWARN },
{ "const_cast", RID_CONSTCAST, D_CXXONLY | D_CXXWARN },
RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
/* C++20 */
- RID_CONSTINIT,
+ RID_CONSTINIT, RID_CONSTEVAL,
/* char8_t */
RID_CHAR8,
2019-11-02 Jakub Jelinek <jakub@redhat.com>
+ PR c++/88335 - Implement P1073R3: Immediate functions
+ * cp-tree.h (struct lang_decl_fn): Add immediate_fn_p bit.
+ (DECL_IMMEDIATE_FUNCTION_P, SET_DECL_IMMEDIATE_FUNCTION_P): Define.
+ (enum cp_decl_spec): Add ds_consteval.
+ (fold_non_dependent_expr): Add another tree argument defaulted to
+ NULL_TREE.
+ * name-lookup.h (struct cp_binding_level): Add immediate_fn_ctx_p
+ member.
+ * parser.c (cp_keyword_starts_decl_specifier_p): Adjust comments
+ for C++11 and C++20 specifiers. Handle RID_CONSTEVAL.
+ (CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR): Adjust comment.
+ (CP_PARSER_FLAGS_CONSTEVAL): New.
+ (cp_parser_skip_balanced_tokens): New forward declaration.
+ (cp_parser_lambda_declarator_opt): Handle ds_consteval. Set
+ current_binding_level->immediate_fn_ctx_p before parsing parameter
+ list if decl-specifier-seq contains consteval specifier.
+ (cp_parser_decl_specifier_seq): Handle RID_CONSTEVAL.
+ (cp_parser_explicit_instantiation): Diagnose explicit instantiation
+ with consteval specifier.
+ (cp_parser_init_declarator): For consteval or into flags
+ CP_PARSER_FLAGS_CONSTEVAL.
+ (cp_parser_direct_declarator): If CP_PARSER_FLAGS_CONSTEVAL, set
+ current_binding_level->immediate_fn_ctx_p in the sk_function_parms
+ scope.
+ (set_and_check_decl_spec_loc): Add consteval entry, formatting fix.
+ * call.c (build_addr_func): For direct calls to immediate functions
+ use build_address rather than decay_conversion.
+ (build_over_call): Evaluate immediate function invocations.
+ * error.c (dump_function_decl): Handle DECL_IMMEDIATE_FUNCTION_P.
+ * semantics.c (expand_or_defer_fn_1): Use tentative linkage and don't
+ call mark_needed for immediate functions.
+ * typeck.c (cxx_sizeof_or_alignof_expr): Likewise. Formatting fix.
+ (cp_build_addr_expr_1): Reject taking address of immediate function
+ outside of immediate function.
+ * decl.c (validate_constexpr_redeclaration): Diagnose consteval
+ vs. non-consteval or vice versa redeclaration. Use
+ SET_DECL_IMMEDIATE_FUNCTION_P if new_decl is immediate function.
+ (check_tag_decl): Use %qs with keyword string to simplify translation.
+ Handle ds_consteval.
+ (start_decl): Adjust diagnostics for static or thread_local variables
+ in immediate functions.
+ (grokfndecl): Call sorry_at on virtual consteval. Use %qs with keyword
+ to string to simplify translation. Diagnose consteval main. Use
+ SET_DECL_IMMEDIATE_FUNCTION_P for consteval.
+ (grokdeclarator): Handle consteval. Use %qs with keyword strings to
+ simplify translation. Use separate ifs instead of chained else if
+ for invalid specifiers. For constinit clear constinit_p rather than
+ constexpr_p.
+ * constexpr.c (find_immediate_fndecl): New function.
+ (cxx_eval_outermost_constant_expr): Allow consteval calls returning
+ void. Diagnose returning address of immediate function from consteval
+ evaluation.
+ (fold_non_dependent_expr_template): Add OBJECT argument, pass it
+ through to cxx_eval_outermost_constant_expr.
+ (fold_non_dependent_expr): Add OBJECT argument, pass it through to
+ fold_non_dependent_expr_template.
+ (fold_non_dependent_init): Adjust fold_non_dependent_expr_template
+ caller.
+ * method.c (defaulted_late_check): Adjust diagnostics for consteval.
+ * lambda.c (maybe_add_lambda_conv_op): Copy over
+ DECL_DECLARED_CONSTEXPR_P and DECL_IMMEDIATE_FUNCTION_P bits from
+ callop to both artificial functions.
+ * init.c (build_value_init): Don't do further processing if
+ build_special_member_call returned a TREE_CONSTANT. Formatting fix.
+
PR c++/91369 - Implement P0784R7: constexpr new
* cp-tree.h (CALL_FROM_NEW_OR_DELETE_P): Define.
* init.c (build_new_1, build_vec_delete_1, build_delete): Set
}
function = build_address (function);
}
+ else if (TREE_CODE (function) == FUNCTION_DECL
+ && DECL_IMMEDIATE_FUNCTION_P (function))
+ function = build_address (function);
else
function = decay_conversion (function, complain, /*reject_builtin=*/false);
addr, nargs, argarray);
if (TREE_THIS_VOLATILE (fn) && cfun)
current_function_returns_abnormally = 1;
+ if (TREE_CODE (fn) == FUNCTION_DECL
+ && DECL_IMMEDIATE_FUNCTION_P (fn)
+ && (current_function_decl == NULL_TREE
+ || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
+ && (current_binding_level->kind != sk_function_parms
+ || !current_binding_level->immediate_fn_ctx_p))
+ {
+ tree obj_arg = NULL_TREE, exprimm = expr;
+ if (DECL_CONSTRUCTOR_P (fn))
+ obj_arg = first_arg;
+ if (obj_arg
+ && is_dummy_object (obj_arg)
+ && !type_dependent_expression_p (obj_arg))
+ {
+ exprimm = build_cplus_new (DECL_CONTEXT (fn), expr, complain);
+ obj_arg = NULL_TREE;
+ }
+ /* Look through *(const T *)&obj. */
+ else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF)
+ {
+ tree addr = TREE_OPERAND (obj_arg, 0);
+ STRIP_NOPS (addr);
+ if (TREE_CODE (addr) == ADDR_EXPR)
+ {
+ tree typeo = TREE_TYPE (obj_arg);
+ tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
+ if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
+ obj_arg = TREE_OPERAND (addr, 0);
+ }
+ }
+ fold_non_dependent_expr (exprimm, complain,
+ /*manifestly_const_eval=*/true,
+ obj_arg);
+ }
return convert_from_reference (expr);
}
if (TREE_CODE (c) == CALL_EXPR)
TREE_NO_WARNING (c) = 1;
}
+ if (TREE_CODE (fn) == ADDR_EXPR)
+ {
+ tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
+ if (TREE_CODE (fndecl) == FUNCTION_DECL
+ && DECL_IMMEDIATE_FUNCTION_P (fndecl)
+ && (current_function_decl == NULL_TREE
+ || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
+ && (current_binding_level->kind != sk_function_parms
+ || !current_binding_level->immediate_fn_ctx_p))
+ {
+ tree obj_arg = NULL_TREE;
+ if (DECL_CONSTRUCTOR_P (fndecl))
+ obj_arg = cand->first_arg ? cand->first_arg : (*args)[0];
+ if (obj_arg && is_dummy_object (obj_arg))
+ {
+ call = build_cplus_new (DECL_CONTEXT (fndecl), call, complain);
+ obj_arg = NULL_TREE;
+ }
+ /* Look through *(const T *)&obj. */
+ else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF)
+ {
+ tree addr = TREE_OPERAND (obj_arg, 0);
+ STRIP_NOPS (addr);
+ if (TREE_CODE (addr) == ADDR_EXPR)
+ {
+ tree typeo = TREE_TYPE (obj_arg);
+ tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
+ if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
+ obj_arg = TREE_OPERAND (addr, 0);
+ }
+ }
+ call = cxx_constant_value (call, obj_arg);
+ }
+ }
return call;
}
return NULL_TREE;
}
+/* Find immediate function decls in *TP if any. */
+
+static tree
+find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/)
+{
+ if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp))
+ return *tp;
+ return NULL_TREE;
+}
+
/* ALLOW_NON_CONSTANT is false if T is required to be a constant expression.
STRICT has the same sense as for constant_value_1: true if we only allow
conforming C++ constant expressions, or false if we want a constant value
tree type = initialized_type (t);
tree r = t;
+ bool is_consteval = false;
if (VOID_TYPE_P (type))
{
if (constexpr_dtor)
/* Used for destructors of array elements. */
type = TREE_TYPE (object);
else
- return t;
+ {
+ if (cxx_dialect < cxx2a)
+ return t;
+ if (TREE_CODE (t) != CALL_EXPR && TREE_CODE (t) != AGGR_INIT_EXPR)
+ return t;
+ /* Calls to immediate functions returning void need to be
+ evaluated. */
+ tree fndecl = cp_get_callee_fndecl_nofold (t);
+ if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl))
+ return t;
+ else
+ is_consteval = true;
+ }
+ }
+ else if (cxx_dialect >= cxx2a
+ && (TREE_CODE (t) == CALL_EXPR
+ || TREE_CODE (t) == AGGR_INIT_EXPR
+ || TREE_CODE (t) == TARGET_EXPR))
+ {
+ tree x = t;
+ if (TREE_CODE (x) == TARGET_EXPR)
+ x = TARGET_EXPR_INITIAL (x);
+ tree fndecl = cp_get_callee_fndecl_nofold (x);
+ if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
+ is_consteval = true;
}
if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
{
}
}
+ /* Check that immediate invocation does not return an expression referencing
+ any immediate function decls. They need to be allowed while parsing
+ immediate functions, but can't leak outside of them. */
+ if (is_consteval
+ && t != r
+ && (current_function_decl == NULL_TREE
+ || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+ if (tree immediate_fndecl
+ = cp_walk_tree_without_duplicates (&r, find_immediate_fndecl,
+ NULL))
+ {
+ if (!allow_non_constant && !non_constant_p)
+ error_at (cp_expr_loc_or_input_loc (t),
+ "immediate evaluation returns address of immediate "
+ "function %qD", immediate_fndecl);
+ r = t;
+ non_constant_p = true;
+ }
+
/* Technically we should check this for all subexpressions, but that
runs into problems with our internal representation of pointer
subtraction and the 5.19 rules are still in flux. */
static tree
fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
- bool manifestly_const_eval)
+ bool manifestly_const_eval,
+ tree object)
{
gcc_assert (processing_template_decl);
tree r = cxx_eval_outermost_constant_expr (t, true, true,
manifestly_const_eval,
- false, NULL_TREE);
+ false, object);
/* cp_tree_equal looks through NOPs, so allow them. */
gcc_checking_assert (r == t
|| CONVERT_EXPR_P (t)
tree
fold_non_dependent_expr (tree t,
tsubst_flags_t complain /* = tf_warning_or_error */,
- bool manifestly_const_eval /* = false */)
+ bool manifestly_const_eval /* = false */,
+ tree object /* = NULL_TREE */)
{
if (t == NULL_TREE)
return NULL_TREE;
if (processing_template_decl)
return fold_non_dependent_expr_template (t, complain,
- manifestly_const_eval);
+ manifestly_const_eval, object);
- return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
+ return maybe_constant_value (t, object, manifestly_const_eval);
}
if (processing_template_decl)
{
t = fold_non_dependent_expr_template (t, complain,
- manifestly_const_eval);
+ manifestly_const_eval, NULL_TREE);
/* maybe_constant_init does this stripping, so do it here too. */
if (TREE_CODE (t) == TARGET_EXPR)
{
unsigned hidden_friend_p : 1;
unsigned omp_declare_reduction_p : 1;
unsigned has_dependent_explicit_spec_p : 1;
- unsigned spare : 12;
+ unsigned immediate_fn_p : 1;
+ unsigned spare : 11;
/* 32-bits padding on 64-bit host. */
#define DECL_DECLARED_CONSTEXPR_P(DECL) \
DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
+/* True if FNDECL is an immediate function. */
+#define DECL_IMMEDIATE_FUNCTION_P(NODE) \
+ (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (STRIP_TEMPLATE (NODE))) \
+ ? LANG_DECL_FN_CHECK (NODE)->immediate_fn_p \
+ : false)
+#define SET_DECL_IMMEDIATE_FUNCTION_P(NODE) \
+ (retrofit_lang_decl (FUNCTION_DECL_CHECK (NODE)), \
+ LANG_DECL_FN_CHECK (NODE)->immediate_fn_p = true)
+
// True if NODE was declared as 'concept'. The flag implies that the
// declaration is constexpr, that the declaration cannot be specialized or
// refined, and that the result type must be convertible to bool.
ds_constexpr,
ds_complex,
ds_constinit,
+ ds_consteval,
ds_thread,
ds_type_spec,
ds_redefined_builtin_type_spec,
extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false);
extern tree fold_non_dependent_expr (tree,
tsubst_flags_t = tf_warning_or_error,
- bool = false);
+ bool = false, tree = NULL_TREE);
extern tree fold_non_dependent_init (tree,
tsubst_flags_t = tf_warning_or_error,
bool = false);
return true;
if (DECL_DECLARED_CONSTEXPR_P (old_decl)
== DECL_DECLARED_CONSTEXPR_P (new_decl))
- return true;
+ {
+ if (TREE_CODE (old_decl) != FUNCTION_DECL)
+ return true;
+ if (DECL_IMMEDIATE_FUNCTION_P (old_decl)
+ == DECL_IMMEDIATE_FUNCTION_P (new_decl))
+ return true;
+ }
if (TREE_CODE (old_decl) == FUNCTION_DECL)
{
if (fndecl_built_in_p (old_decl))
/* Hide a built-in declaration. */
DECL_DECLARED_CONSTEXPR_P (old_decl)
= DECL_DECLARED_CONSTEXPR_P (new_decl);
+ if (DECL_IMMEDIATE_FUNCTION_P (new_decl))
+ SET_DECL_IMMEDIATE_FUNCTION_P (old_decl);
return true;
}
/* 7.1.5 [dcl.constexpr]
&& DECL_TEMPLATE_SPECIALIZATION (new_decl))
return true;
+ const char *kind = "constexpr";
+ if (DECL_IMMEDIATE_FUNCTION_P (old_decl)
+ || DECL_IMMEDIATE_FUNCTION_P (new_decl))
+ kind = "consteval";
error_at (DECL_SOURCE_LOCATION (new_decl),
- "redeclaration %qD differs in %<constexpr%> "
- "from previous declaration", new_decl);
+ "redeclaration %qD differs in %qs "
+ "from previous declaration", new_decl,
+ kind);
inform (DECL_SOURCE_LOCATION (old_decl),
"previous declaration %qD", old_decl);
return false;
else if (saw_typedef)
warning_at (declspecs->locations[ds_typedef], 0,
"%<typedef%> was ignored in this declaration");
- else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr))
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr))
error_at (declspecs->locations[ds_constexpr],
- "%<constexpr%> cannot be used for type declarations");
- else if (decl_spec_seq_has_spec_p (declspecs, ds_constinit))
+ "%qs cannot be used for type declarations", "constexpr");
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_constinit))
error_at (declspecs->locations[ds_constinit],
- "%<constinit%> cannot be used for type declarations");
+ "%qs cannot be used for type declarations", "constinit");
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_consteval))
+ error_at (declspecs->locations[ds_consteval],
+ "%qs cannot be used for type declarations", "consteval");
}
if (declspecs->attributes && warn_attributes && declared_type)
bool ok = false;
if (CP_DECL_THREAD_LOCAL_P (decl))
error_at (DECL_SOURCE_LOCATION (decl),
- "%qD declared %<thread_local%> in %<constexpr%> function",
- decl);
+ "%qD declared %<thread_local%> in %qs function", decl,
+ DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+ ? "consteval" : "constexpr");
else if (TREE_STATIC (decl))
error_at (DECL_SOURCE_LOCATION (decl),
- "%qD declared %<static%> in %<constexpr%> function", decl);
+ "%qD declared %<static%> in %qs function", decl,
+ DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+ ? "consteval" : "constexpr");
else
ok = true;
if (!ok)
}
}
+ /* FIXME: For now. */
+ if (virtualp && (inlinep & 8) != 0)
+ {
+ sorry_at (DECL_SOURCE_LOCATION (decl),
+ "%<virtual%> %<consteval%> method %qD not supported yet",
+ decl);
+ inlinep &= ~8;
+ }
+
/* If this decl has namespace scope, set that up. */
if (in_namespace)
set_decl_namespace (decl, in_namespace, friendp);
"cannot declare %<::main%> to be inline");
if (inlinep & 2)
error_at (declspecs->locations[ds_constexpr],
- "cannot declare %<::main%> to be %<constexpr%>");
+ "cannot declare %<::main%> to be %qs", "constexpr");
+ if (inlinep & 8)
+ error_at (declspecs->locations[ds_consteval],
+ "cannot declare %<::main%> to be %qs", "consteval");
if (!publicp)
error_at (location, "cannot declare %<::main%> to be static");
inlinep = 0;
}
if (inlinep & 2)
DECL_DECLARED_CONSTEXPR_P (decl) = true;
+ else if (inlinep & 8)
+ {
+ DECL_DECLARED_CONSTEXPR_P (decl) = true;
+ SET_DECL_IMMEDIATE_FUNCTION_P (decl);
+ }
// If the concept declaration specifier was found, check
// that the declaration satisfies the necessary requirements.
bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit);
+ bool consteval_p = decl_spec_seq_has_spec_p (declspecs, ds_consteval);
bool late_return_type_p = false;
bool array_parameter_p = false;
tree reqs = NULL_TREE;
if (name == NULL)
name = decl_context == PARM ? "parameter" : "type name";
+ if (consteval_p && constexpr_p)
+ {
+ error_at (declspecs->locations[ds_consteval],
+ "both %qs and %qs specified", "constexpr", "consteval");
+ return error_mark_node;
+ }
+
if (concept_p && typedef_p)
{
error_at (declspecs->locations[ds_concept],
- "%<concept%> cannot appear in a typedef declaration");
+ "%qs cannot appear in a typedef declaration", "concept");
return error_mark_node;
}
if (constexpr_p && typedef_p)
{
error_at (declspecs->locations[ds_constexpr],
- "%<constexpr%> cannot appear in a typedef declaration");
+ "%qs cannot appear in a typedef declaration", "constexpr");
+ return error_mark_node;
+ }
+
+ if (consteval_p && typedef_p)
+ {
+ error_at (declspecs->locations[ds_consteval],
+ "%qs cannot appear in a typedef declaration", "consteval");
return error_mark_node;
}
/* Function parameters cannot be concept. */
if (concept_p)
- error_at (declspecs->locations[ds_concept],
- "a parameter cannot be declared %<concept%>");
+ {
+ error_at (declspecs->locations[ds_concept],
+ "a parameter cannot be declared %qs", "concept");
+ concept_p = 0;
+ constexpr_p = 0;
+ }
/* Function parameters cannot be constexpr. If we saw one, moan
and pretend it wasn't there. */
else if (constexpr_p)
{
error_at (declspecs->locations[ds_constexpr],
- "a parameter cannot be declared %<constexpr%>");
+ "a parameter cannot be declared %qs", "constexpr");
constexpr_p = 0;
}
- else if (constinit_p)
+ if (constinit_p)
{
error_at (declspecs->locations[ds_constinit],
- "a parameter cannot be declared %<constinit%>");
- constexpr_p = 0;
+ "a parameter cannot be declared %qs", "constinit");
+ constinit_p = 0;
+ }
+ if (consteval_p)
+ {
+ error_at (declspecs->locations[ds_consteval],
+ "a parameter cannot be declared %qs", "consteval");
+ consteval_p = 0;
}
}
if (typedef_p)
error_at (declspecs->locations[ds_typedef],
"structured binding declaration cannot be %qs", "typedef");
- if (constexpr_p)
+ if (constexpr_p && !concept_p)
error_at (declspecs->locations[ds_constexpr], "structured "
"binding declaration cannot be %qs", "constexpr");
+ if (consteval_p)
+ error_at (declspecs->locations[ds_consteval], "structured "
+ "binding declaration cannot be %qs", "consteval");
if (thread_p && cxx_dialect < cxx2a)
pedwarn (declspecs->locations[ds_thread], 0,
"structured binding declaration can be %qs only in "
inlinep = 0;
typedef_p = 0;
constexpr_p = 0;
+ consteval_p = 0;
concept_p = 0;
if (storage_class != sc_static)
{
if (concept_p)
{
error_at (declspecs->locations[ds_concept],
- "a destructor cannot be %<concept%>");
+ "a destructor cannot be %qs", "concept");
return error_mark_node;
}
if (constexpr_p && cxx_dialect < cxx2a)
" with %<-std=c++2a%> or %<-std=gnu++2a%>");
return error_mark_node;
}
+ if (consteval_p)
+ {
+ error_at (declspecs->locations[ds_consteval],
+ "a destructor cannot be %qs", "consteval");
+ return error_mark_node;
+ }
}
else if (sfk == sfk_constructor && friendp && !ctype)
{
"a concept cannot be a member function");
concept_p = false;
}
+ else if (consteval_p
+ && identifier_p (unqualified_id)
+ && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+ {
+ error_at (declspecs->locations[ds_consteval],
+ "%qD cannot be %qs", unqualified_id, "consteval");
+ consteval_p = false;
+ }
if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
{
reqs,
virtualp, flags, memfn_quals, rqual, raises,
friendp ? -1 : 0, friendp, publicp,
- inlinep | (2 * constexpr_p) | (4 * concept_p),
+ inlinep | (2 * constexpr_p) | (4 * concept_p)
+ | (8 * consteval_p),
initialized == SD_DELETED, sfk,
funcdef_flag, late_return_type_p,
template_count, in_namespace,
set_linkage_for_static_data_member (decl);
if (concept_p)
error_at (declspecs->locations[ds_concept],
- "static data member %qE declared %<concept%>",
- unqualified_id);
+ "static data member %qE declared %qs",
+ unqualified_id, "concept");
else if (constexpr_p && !initialized)
{
error_at (DECL_SOURCE_LOCATION (decl),
"have an initializer", decl);
constexpr_p = false;
}
+ if (consteval_p)
+ error_at (declspecs->locations[ds_consteval],
+ "static data member %qE declared %qs",
+ unqualified_id, "consteval");
if (inlinep)
mark_inline_variable (decl, declspecs->locations[ds_inline]);
else
{
if (concept_p)
- error_at (declspecs->locations[ds_concept],
- "non-static data member %qE declared %<concept%>",
- unqualified_id);
- else if (constexpr_p)
+ {
+ error_at (declspecs->locations[ds_concept],
+ "non-static data member %qE declared %qs",
+ unqualified_id, "concept");
+ concept_p = false;
+ constexpr_p = false;
+ }
+ else if (constexpr_p)
{
error_at (declspecs->locations[ds_constexpr],
- "non-static data member %qE declared "
- "%<constexpr%>", unqualified_id);
+ "non-static data member %qE declared %qs",
+ unqualified_id, "constexpr");
constexpr_p = false;
}
- else if (constinit_p)
+ if (constinit_p)
{
error_at (declspecs->locations[ds_constinit],
- "non-static data member %qE declared "
- "%<constinit%>", unqualified_id);
+ "non-static data member %qE declared %qs",
+ unqualified_id, "constinit");
constinit_p = false;
}
+ if (consteval_p)
+ {
+ error_at (declspecs->locations[ds_consteval],
+ "non-static data member %qE declared %qs",
+ unqualified_id, "consteval");
+ consteval_p = false;
+ }
decl = build_decl (id_loc, FIELD_DECL, unqualified_id, type);
DECL_NONADDRESSABLE_P (decl) = bitfield;
if (bitfield && !unqualified_id)
sfk = sfk_none;
}
}
+ if (consteval_p
+ && identifier_p (unqualified_id)
+ && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+ {
+ error_at (declspecs->locations[ds_consteval],
+ "%qD cannot be %qs", unqualified_id, "consteval");
+ consteval_p = false;
+ }
/* Record whether the function is public. */
publicp = (ctype != NULL_TREE
reqs, virtualp, flags, memfn_quals, rqual, raises,
1, friendp,
publicp,
- inlinep | (2 * constexpr_p) | (4 * concept_p),
+ inlinep | (2 * constexpr_p) | (4 * concept_p)
+ | (8 * consteval_p),
initialized == SD_DELETED,
sfk,
funcdef_flag,
"is not a definition", decl);
constexpr_p = false;
}
+ if (consteval_p)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "a variable cannot be declared %<consteval%>");
+ consteval_p = false;
+ }
if (inlinep)
mark_inline_variable (decl, declspecs->locations[ds_inline]);
invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
/* Perform delayed folding before NRV transformation. */
- if (!processing_template_decl)
+ if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl))
cp_fold_function (fndecl);
/* Set up the named return value optimization, if we can. Candidate
do_warn_unused_parameter (fndecl);
/* Genericize before inlining. */
- if (!processing_template_decl)
+ if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl))
cp_genericize (fndecl);
/* We're leaving the context of this function, so zap cfun. It's still in
{
if (DECL_DECLARED_CONCEPT_P (t))
pp_cxx_ws_string (pp, "concept");
- else
+ else if (DECL_IMMEDIATE_FUNCTION_P (t))
+ pp_cxx_ws_string (pp, "consteval");
+ else
pp_cxx_ws_string (pp, "constexpr");
}
}
gcc_assert (!processing_template_decl
|| (SCALAR_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE));
- if (CLASS_TYPE_P (type)
- && type_build_ctor_call (type))
+ if (CLASS_TYPE_P (type) && type_build_ctor_call (type))
{
- tree ctor =
- build_special_member_call (NULL_TREE, complete_ctor_identifier,
- NULL, type, LOOKUP_NORMAL,
- complain);
- if (ctor == error_mark_node)
+ tree ctor
+ = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+ NULL, type, LOOKUP_NORMAL, complain);
+ if (ctor == error_mark_node || TREE_CONSTANT (ctor))
return ctor;
tree fn = NULL_TREE;
if (TREE_CODE (ctor) == CALL_EXPR)
DECL_ARTIFICIAL (fn) = 1;
DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1;
+ DECL_DECLARED_CONSTEXPR_P (fn) = DECL_DECLARED_CONSTEXPR_P (callop);
+ if (DECL_IMMEDIATE_FUNCTION_P (callop))
+ SET_DECL_IMMEDIATE_FUNCTION_P (fn);
DECL_ARGUMENTS (fn) = build_this_parm (fn, fntype, TYPE_QUAL_CONST);
if (nested_def)
DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1;
DECL_STATIC_FUNCTION_P (fn) = 1;
+ DECL_DECLARED_CONSTEXPR_P (fn) = DECL_DECLARED_CONSTEXPR_P (callop);
+ if (DECL_IMMEDIATE_FUNCTION_P (callop))
+ SET_DECL_IMMEDIATE_FUNCTION_P (fn);
DECL_ARGUMENTS (fn) = fn_args;
for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
{
if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
{
error ("explicitly defaulted function %q+D cannot be declared "
- "%qs because the implicit declaration is not %qs:",
- fn, "constexpr", "constexpr");
+ "%qs because the implicit declaration is not %qs:", fn,
+ DECL_IMMEDIATE_FUNCTION_P (fn) ? "consteval" : "constexpr",
+ "constexpr");
explain_implicit_non_constexpr (fn);
}
DECL_DECLARED_CONSTEXPR_P (fn) = false;
'this_entity'. */
unsigned defining_class_p : 1;
- /* 23 bits left to fill a 32-bit word. */
+ /* true for SK_FUNCTION_PARMS of immediate functions. */
+ unsigned immediate_fn_ctx_p : 1;
+
+ /* 22 bits left to fill a 32-bit word. */
};
/* The binding level currently in effect. */
/* GNU extensions. */
case RID_ATTRIBUTE:
case RID_TYPEOF:
- /* C++0x extensions. */
+ /* C++11 extensions. */
case RID_DECLTYPE:
case RID_UNDERLYING_TYPE:
case RID_CONSTEXPR:
+ /* C++20 extensions. */
case RID_CONSTINIT:
+ case RID_CONSTEVAL:
return true;
default:
/* When parsing a decl-specifier-seq, only allow type-specifier or
constexpr. */
CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8,
- /* When parsing a decl-specifier-seq, only allow mutable or constexpr. */
+ /* When parsing a decl-specifier-seq, only allow mutable, constexpr or
+ for C++2A consteval. */
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
/* When parsing a decl-specifier-seq, allow missing typename. */
CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20,
/* When parsing of the noexcept-specifier should be delayed. */
- CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40
+ CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40,
+ /* When parsing a consteval declarator. */
+ CP_PARSER_FLAGS_CONSTEVAL = 0x80
};
/* This type is used for parameters and variables which hold
(cp_parser *);
static bool cp_parser_skip_to_closing_square_bracket
(cp_parser *);
+static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t);
// -------------------------------------------------------------------------- //
// Unevaluated Operand Guard
opening parenthesis if present. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
+ bool is_consteval = false;
+ /* For C++20, before parsing the parameter list check if there is
+ a consteval specifier in the corresponding decl-specifier-seq. */
+ if (cxx_dialect >= cxx2a)
+ {
+ for (size_t n = cp_parser_skip_balanced_tokens (parser, 1);
+ cp_lexer_nth_token_is (parser->lexer, n, CPP_KEYWORD); n++)
+ {
+ if (cp_lexer_peek_nth_token (parser->lexer, n)->keyword
+ == RID_CONSTEVAL)
+ {
+ is_consteval = true;
+ break;
+ }
+ }
+ }
+
matching_parens parens;
parens.consume_open (parser);
begin_scope (sk_function_parms, /*entity=*/NULL_TREE);
+ if (is_consteval)
+ current_binding_level->immediate_fn_ctx_p = true;
+
/* Parse parameters. */
param_list
= cp_parser_parameter_declaration_clause
"lambda only available with %<-std=c++17%> or "
"%<-std=gnu++17%>");
}
+ if (lambda_specs.locations[ds_consteval])
+ return_type_specs.locations[ds_consteval]
+ = lambda_specs.locations[ds_consteval];
p = obstack_alloc (&declarator_obstack, 0);
cp_lexer_consume_token (parser->lexer);
break;
+ case RID_CONSTEVAL:
+ ds = ds_consteval;
+ cp_lexer_consume_token (parser->lexer);
+ break;
+
case RID_CONCEPT:
ds = ds_concept;
cp_lexer_consume_token (parser->lexer);
if (found_decl_spec
&& (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
&& token->keyword != RID_MUTABLE
- && token->keyword != RID_CONSTEXPR)
+ && token->keyword != RID_CONSTEXPR
+ && token->keyword != RID_CONSTEVAL)
error_at (token->location, "%qD invalid in lambda",
ridpointers[token->keyword]);
permerror (decl_specifiers.locations[ds_constexpr],
"explicit instantiation shall not use"
" %<constexpr%> specifier");
+ if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_consteval))
+ permerror (decl_specifiers.locations[ds_consteval],
+ "explicit instantiation shall not use"
+ " %<consteval%> specifier");
decl = grokdeclarator (declarator, &decl_specifiers,
NORMAL, 0, &decl_specifiers.attributes);
bool saved_default_arg_ok_p = parser->default_arg_ok_p;
location_t tmp_init_loc = UNKNOWN_LOCATION;
+ if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval))
+ flags |= CP_PARSER_FLAGS_CONSTEVAL;
+
/* Gather the attributes that were provided with the
decl-specifiers. */
prefix_attributes = decl_specifiers->attributes;
begin_scope (sk_function_parms, NULL_TREE);
+ /* Signal we are in the immediate function context. */
+ if (flags & CP_PARSER_FLAGS_CONSTEVAL)
+ current_binding_level->immediate_fn_ctx_p = true;
+
/* Parse the parameter-declaration-clause. */
params
= cp_parser_parameter_declaration_clause (parser, flags);
"friend",
"typedef",
"using",
- "constexpr",
+ "constexpr",
"__complex",
- "constinit"
+ "constinit",
+ "consteval"
};
gcc_rich_location richloc (location);
richloc.add_fixit_remove ();
if (DECL_INTERFACE_KNOWN (fn))
/* We've already made a decision as to how this function will
be handled. */;
- else if (!at_eof)
+ else if (!at_eof || DECL_IMMEDIATE_FUNCTION_P (fn))
tentative_decl_linkage (fn);
else
import_export_decl (fn);
be emitted; there may be callers in other DLLs. */
if (DECL_DECLARED_INLINE_P (fn)
&& !DECL_REALLY_EXTERN (fn)
+ && !DECL_IMMEDIATE_FUNCTION_P (fn)
&& (flag_keep_inline_functions
|| (flag_keep_inline_dllexport
&& lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))))
if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
{
tree stripped_arg = tree_strip_any_location_wrapper (arg);
+ if (TREE_CODE (stripped_arg) == FUNCTION_DECL
+ && DECL_IMMEDIATE_FUNCTION_P (stripped_arg)
+ && (current_function_decl == NULL_TREE
+ || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+ {
+ if (complain & tf_error)
+ error ("taking address of an immediate function %qD",
+ stripped_arg);
+ return error_mark_node;
+ }
if (TREE_CODE (stripped_arg) == FUNCTION_DECL
&& !mark_used (stripped_arg, complain) && !(complain & tf_error))
return error_mark_node;
2019-11-02 Jakub Jelinek <jakub@redhat.com>
+ PR c++/88335 - Implement P1073R3: Immediate functions
+ * g++.dg/cpp2a/consteval1.C: New test.
+ * g++.dg/cpp2a/consteval2.C: New test.
+ * g++.dg/cpp2a/consteval3.C: New test.
+ * g++.dg/cpp2a/consteval4.C: New test.
+ * g++.dg/cpp2a/consteval5.C: New test.
+ * g++.dg/cpp2a/consteval6.C: New test.
+ * g++.dg/cpp2a/consteval7.C: New test.
+ * g++.dg/cpp2a/consteval8.C: New test.
+ * g++.dg/cpp2a/consteval9.C: New test.
+ * g++.dg/cpp2a/consteval10.C: New test.
+ * g++.dg/cpp2a/consteval11.C: New test.
+ * g++.dg/cpp2a/consteval12.C: New test.
+ * g++.dg/cpp2a/consteval13.C: New test.
+ * g++.dg/cpp2a/consteval14.C: New test.
+ * g++.dg/ext/consteval1.C: New test.
+
PR c++/91369 - Implement P0784R7: constexpr new
* g++.dg/cpp2a/constexpr-new6.C: New test.
* g++.dg/cpp2a/constexpr-new7.C: New test.
--- /dev/null
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+namespace std {
+ constexpr inline bool
+ is_constant_evaluated () noexcept
+ {
+ return __builtin_is_constant_evaluated ();
+ }
+}
+
+extern "C" void abort ();
+constexpr int f0 (int n) { return n; }
+consteval int f1 (int n) { return f0 (n) * n; }
+consteval int f2 (int n) { return f1 (n); }
+consteval bool f3 () { return std::is_constant_evaluated (); }
+struct S { constexpr S (int x) : s (x) {} consteval int m1 (int n) const; int s; };
+consteval int
+S::m1 (int n) const
+{
+ n += s;
+ return n;
+}
+
+constexpr int a = 2;
+int b = f1 (a);
+int c = f2 (f1 (a));
+bool d = f3 ();
+constexpr S e = 41;
+int f = e.m1 (1);
+
+int
+main ()
+{
+ if (b != 4 || c != 16 || !d || f != 42)
+ abort ();
+}
--- /dev/null
+// { dg-do compile }
+
+consteval int bar (void) { return 0; } // { dg-error "'consteval' does not name a type" "" { target c++17_down } }
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar (int i) { if (i != 1) throw 1; return 0; } // { dg-error "is not a constant expression" }
+
+constexpr int a = bar (1);
+constexpr int b = bar (2); // { dg-message "in 'constexpr' expansion of" }
+constexpr int c = 0 ? bar (3) : 1; // { dg-message "in 'constexpr' expansion of" }
+const int d = bar (4); // { dg-message "in 'constexpr' expansion of" }
+const int e = 0 ? bar (5) : 1; // { dg-message "in 'constexpr' expansion of" }
+int f = bar (1);
+int g = bar (6); // { dg-message "in 'constexpr' expansion of" }
+int h = 0 ? bar (7) : 1; // { dg-message "in 'constexpr' expansion of" }
+
+void
+foo ()
+{
+ constexpr int a = bar (1);
+ constexpr int b = bar (2); // { dg-message "in 'constexpr' expansion of" }
+ constexpr int c = 0 ? bar (3) : 1; // { dg-message "in 'constexpr' expansion of" }
+ const int d = bar (4); // { dg-message "in 'constexpr' expansion of" }
+ const int e = 0 ? bar (5) : 1; // { dg-message "in 'constexpr' expansion of" }
+ int f = bar (1);
+ int g = bar (6); // { dg-message "in 'constexpr' expansion of" }
+ int h = 0 ? bar (7) : 1; // { dg-message "in 'constexpr' expansion of" }
+ h += 0 ? bar (8) : 1; // { dg-message "in 'constexpr' expansion of" }
+ if (0)
+ bar (9); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar (10); // { dg-message "in 'constexpr' expansion of" }
+ if (1)
+ bar (11); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar (12); // { dg-message "in 'constexpr' expansion of" }
+ if constexpr (0)
+ bar (13); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar (14); // { dg-message "in 'constexpr' expansion of" }
+ if constexpr (1)
+ bar (15); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar (16); // { dg-message "in 'constexpr' expansion of" }
+}
+
+consteval int
+baz ()
+{
+ constexpr int a = bar (1);
+ constexpr int b = bar (2); // { dg-message "in 'constexpr' expansion of" }
+ constexpr int c = 0 ? bar (3) : 1;
+ const int d = bar (4);
+ const int e = 0 ? bar (5) : 1;
+ int f = bar (1);
+ int g = bar (6);
+ int h = 0 ? bar (7) : 1;
+ h += 0 ? bar (8) : 1;
+ if (0)
+ bar (9);
+ else
+ bar (10);
+ if (1)
+ bar (11);
+ else
+ bar (12);
+ if constexpr (0)
+ bar (13);
+ else
+ bar (14);
+ if constexpr (1)
+ bar (15);
+ else
+ bar (16);
+ return 0;
+}
+
+template <typename T>
+void
+qux ()
+{
+ if (0)
+ bar (2); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar (3); // { dg-message "in 'constexpr' expansion of" }
+ if (1)
+ bar (4); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar (5); // { dg-message "in 'constexpr' expansion of" }
+ if constexpr (0)
+ bar (6); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar (7); // { dg-message "in 'constexpr' expansion of" }
+ if constexpr (1)
+ bar (8); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar (9); // { dg-message "in 'constexpr' expansion of" }
+ if (0)
+ bar ((T) 2);
+ else
+ bar ((T) 3);
+ if (1)
+ bar ((T) 4);
+ else
+ bar ((T) 5);
+ if constexpr (0)
+ bar ((T) 6);
+ else
+ bar ((T) 7);
+ if constexpr (1)
+ bar ((T) 8);
+ else
+ bar ((T) 9);
+}
+
+template <typename T>
+void
+quux ()
+{
+ if (0)
+ bar ((T) 2); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar ((T) 3); // { dg-message "in 'constexpr' expansion of" }
+ if (1)
+ bar ((T) 4); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar ((T) 5); // { dg-message "in 'constexpr' expansion of" }
+ if constexpr (0)
+ bar ((T) 6);
+ else
+ bar ((T) 7); // { dg-message "in 'constexpr' expansion of" }
+ if constexpr (1)
+ bar ((T) 8); // { dg-message "in 'constexpr' expansion of" }
+ else
+ bar ((T) 9);
+}
+
+void
+corge ()
+{
+ quux <int> ();
+}
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar () { return 42; }
+consteval int baz () { return 1; }
+typedef int (*fnptr) ();
+consteval fnptr quux () { return bar; }
+
+void
+foo ()
+{
+ auto qux = [] (fnptr a = quux ()) consteval { return a (); };
+ constexpr auto e = qux ();
+ static_assert (e == 42);
+}
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar () { return 42; }
+consteval int baz () { return 1; }
+typedef int (*fnptr) ();
+consteval fnptr quux () { return bar; }
+
+void
+foo ()
+{
+ auto qux = [] (fnptr a = quux ()) consteval { return a (); };
+ constexpr auto c = qux (baz); // { dg-error "taking address of an immediate function" }
+ constexpr auto d = qux (bar); // { dg-error "taking address of an immediate function" }
+ static_assert (c == 1);
+ static_assert (d == 42);
+}
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } consteval S (int x) : a (x), b (x) { a++; b--; } int a, b; };
+S c;
+
+template <int N>
+int
+foo ()
+{
+ S a;
+ a.b++;
+ c = a;
+ S b = 12;
+ c.a += b.a;
+ c.b += b.b;
+ S e[2];
+ S f[2] = { 1, 2 };
+ const S g;
+ c.a += g.a;
+ c.b += g.b;
+ const S h = 12;
+ c.a += h.a;
+ c.b += h.b;
+ const S i[2];
+ const S j[2] = { 1, 2 };
+ return S ().a + e[1].a + f[0].b + i[0].a + j[1].b;
+}
+
+int x = foo <2> ();
--- /dev/null
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+extern "C" void abort ();
+consteval int foo () { return 42; }
+consteval auto bar () { return foo; }
+consteval int baz (int (*fn) () = bar ()) { return fn (); }
+constexpr int a = baz ();
+static_assert (a == 42);
+int b = baz ();
+
+int
+main ()
+{
+ if (b != 42)
+ abort ();
+}
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { S () : a (0), b (1) {} int a, b; };
+int f1 (); // { dg-message "previous declaration 'int f1\\(\\)'" }
+consteval int f1 (); // { dg-error "redeclaration 'consteval int f1\\(\\)' differs in 'consteval' from previous declaration" }
+consteval int f2 (); // { dg-message "previous declaration 'consteval int f2\\(\\)'" }
+int f2 (); // { dg-error "redeclaration 'int f2\\(\\)' differs in 'consteval' from previous declaration" }
+constexpr int f3 (); // { dg-message "previous declaration 'constexpr int f3\\(\\)'" }
+consteval int f3 (); // { dg-error "redeclaration 'consteval int f3\\(\\)' differs in 'consteval' from previous declaration" }
+consteval int f4 (); // { dg-message "previous declaration 'consteval int f4\\(\\)'" }
+constexpr int f4 (); // { dg-error "redeclaration 'constexpr int f4\\(\\)' differs in 'consteval' from previous declaration" }
+typedef consteval int cint; // { dg-error "'consteval' cannot appear in a typedef declaration" }
+consteval struct T { int i; }; // { dg-error "'consteval' cannot be used for type declarations" }
+consteval int a = 5; // { dg-error "a variable cannot be declared 'consteval'" }
+consteval auto [ b, c ] = S (); // { dg-error "structured binding declaration cannot be 'consteval'" }
+int f5 (consteval int x) { return x; } // { dg-error "a parameter cannot be declared 'consteval'" }
+consteval int f6 (int x) { return x; }
+int d = 6; // { dg-message "'int d' is not const" }
+int e = f6 (d); // { dg-error "the value of 'd' is not usable in a constant expression" }
+constexpr int f7 (int x) { return f6 (x); } // { dg-error "'x' is not a constant expression" }
+constexpr int f = f7 (5); // { dg-error "" }
+ // { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
+using fnptr = int (int);
+fnptr *g = f6; // { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
+int f8 (fnptr *);
+int h = f8 (f6); // { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
+consteval constexpr int f9 () { return 0; } // { dg-error "both 'constexpr' and 'consteval' specified" }
+constexpr consteval int f10 () { return 0; } // { dg-error "both 'constexpr' and 'consteval' specified" }
+consteval consteval int f11 () { return 0; } // { dg-error "duplicate 'consteval'" }
+struct U { consteval ~U () {} }; // { dg-error "a destructor cannot be 'consteval'" }
+struct V { consteval int v = 5; }; // { dg-error "non-static data member 'v' declared 'consteval'" }
+struct W { consteval static int w; }; // { dg-error "static data member 'w' declared 'consteval'" }
+int i = sizeof (&f6); // { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
+using j = decltype (&f6); // { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
+int k = sizeof (f6 (d)); // { dg-error "the value of 'd' is not usable in a constant expression" }
+using l = decltype (f6 (d)); // { dg-error "the value of 'd' is not usable in a constant expression" }
+bool m = noexcept (f6 (d)); // { dg-error "the value of 'd' is not usable in a constant expression" }
+namespace std {
+using size_t = decltype (sizeof (0));
+}
+consteval void* operator new (std::size_t); // { dg-error "'operator new' cannot be 'consteval'" }
+consteval void operator delete (void *, std::size_t) noexcept; // { dg-error "'operator delete' cannot be 'consteval'" }
+consteval void operator delete[] (void *) noexcept; // { dg-error "'operator delete \\\[\\\]' cannot be 'consteval'" }
+struct X {
+ static consteval void* operator new (std::size_t); // { dg-error "'operator new' cannot be 'consteval'" }
+ static consteval void operator delete (void *, std::size_t) noexcept; // { dg-error "'operator delete' cannot be 'consteval'" }
+ consteval static void operator delete[] (void *) noexcept; // { dg-error "'operator delete \\\[\\\]' cannot be 'consteval'" }
+};
+consteval int main () { return 0; } // { dg-error "cannot declare '::main' to be 'consteval'" }
+struct A { A (); int a; }; // { dg-message "defaulted constructor calls non-'constexpr' 'A::A\\(\\)'" }
+struct B { constexpr B () : b (0) {} int b; };
+struct C { A a; consteval C () = default; }; // { dg-error "explicitly defaulted function 'consteval C::C\\(\\)' cannot be declared 'consteval' because the implicit declaration is not 'constexpr'" }
+struct D { B b; consteval D () = default; };
+template <class T> consteval T f12 (T x) { return x; }
+template consteval float f12 (float x); // { dg-error "explicit instantiation shall not use 'consteval' specifier" }
+consteval int
+f13 (int x)
+{
+ static int a = 5; // { dg-error "'a' declared 'static' in 'consteval' function" }
+ thread_local int b = 6; // { dg-error "'b' declared 'thread_local' in 'consteval' function" }
+ return x;
+}
--- /dev/null
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+extern "C" void abort ();
+namespace std {
+ constexpr inline bool
+ is_constant_evaluated () noexcept
+ {
+ return __builtin_is_constant_evaluated ();
+ }
+}
+
+int
+main ()
+{
+ constexpr int a = 5;
+ auto b = [] (int n) consteval { return n + a + std::is_constant_evaluated (); };
+ int c = b (4);
+ if (c != 10)
+ abort ();
+ auto d = [] () consteval { return a + std::is_constant_evaluated (); };
+ int e = d ();
+ if (e != 6)
+ abort ();
+ constexpr int f = d ();
+ if (f != 6)
+ abort ();
+ static_assert (d () == 6);
+}
--- /dev/null
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+namespace std {
+ constexpr inline bool
+ is_constant_evaluated () noexcept
+ {
+ return __builtin_is_constant_evaluated ();
+ }
+}
+
+extern "C" void abort ();
+template <int N>
+constexpr int f0 (int n) { return n + N; }
+template <int N>
+consteval int f1 (int n) { return f0<N> (n) * n + N; }
+template <int N>
+consteval int f2 (int n) { return f1<N> (n); }
+template <int N>
+consteval bool f3 () { return std::is_constant_evaluated () + N; }
+struct S { constexpr S (int x) : s (x) {} template <int N> consteval int m1 (int n) const; int s; };
+template <int N>
+consteval int
+S::m1 (int n) const
+{
+ n += s + N;
+ return n;
+}
+
+constexpr int a = 2;
+int b = f1<0> (a);
+int c = f2<0> (f1<0> (a));
+bool d = f3<0> ();
+constexpr S e = 41;
+int f = e.m1<0> (1);
+
+int
+main ()
+{
+ if (b != 4 || c != 16 || !d || f != 42)
+ abort ();
+}
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct A {
+ constexpr A () {}
+ A (A const&) = delete; // { dg-message "declared here" }
+};
+
+template<typename T>
+constexpr void
+foo ()
+{
+ T t;
+ T u = t;
+}
+
+template<typename T>
+consteval void
+bar ()
+{
+ T t;
+ T u = t; // { dg-error "use of deleted function" }
+}
+
+using B = decltype (foo<A> ());
+using C = decltype (bar<A> ()); // { dg-message "required from here" }
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int foo () { return 42; }
+consteval auto bar () { return foo; }
+constexpr auto a = bar (); // { dg-error "immediate evaluation returns address of immediate function 'consteval int foo\\(\\)'" }
+struct S { int b; int (*c) (); };
+consteval S baz () { return { 5, foo }; }
+consteval int qux () { S s = baz (); return s.b + s.c (); }
+consteval int quux () { constexpr S s = baz (); return s.b + s.c (); }
+constexpr auto d = baz (); // { dg-error "immediate evaluation returns address of immediate function 'consteval int foo\\(\\)'" }
+constexpr auto e = qux ();
+constexpr auto f = quux ();
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } consteval S (int x) : a (x), b (x) { a++; b--; } int a, b; };
+S c;
+S d = 25;
+
+int
+foo ()
+{
+ S a;
+ a.b++;
+ c = a;
+ S b = 12;
+ c.a += b.a;
+ c.b += b.b;
+ S e[2];
+ S f[2] = { 1, 2 };
+ return S ().a + e[1].a + f[0].b;
+}
+
+constexpr S g;
+constexpr S h = 42;
+constexpr S i[2];
+constexpr S j[2] = { 3, 4 };
+static_assert (g.a == 2 && g.b == 3);
+static_assert (h.a == 43 && h.b == 41);
+static_assert (i[0].a == 2 && i[0].b == 3 && i[1].a == 2 && i[1].b == 3);
+static_assert (j[0].a == 4 && j[0].b == 2 && j[1].a == 5 && j[1].b == 3);
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar (int i) { if (i != 1) throw 1; return 0; } // { dg-error "is not a constant expression" }
+
+template <int N>
+void foo ()
+{
+ int a = bar (N);
+}
+
+template <int N>
+void qux ()
+{
+ int a = bar (N); // { dg-message "in 'constexpr' expansion of 'bar\\(2\\)'" }
+}
+
+template <int N>
+void quux ()
+{
+ int a = bar (5); // { dg-message "in 'constexpr' expansion of 'bar\\(5\\)'" }
+}
+
+void
+baz ()
+{
+ foo<1> ();
+ qux<2> ();
+}
+
+int a = bar (2); // { dg-message "in 'constexpr' expansion of 'bar\\(2\\)'" }
--- /dev/null
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int foo (int x) { return x; }
+int d = 6; // { dg-message "'int d' is not const" }
+bool e = __builtin_has_attribute (foo (d), packed); // { dg-error "the value of 'd' is not usable in a constant expression" }