@@ -11534,37 +11534,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
non_constant_p = true;
}
- /* Detect consteval-only smuggling: turning a consteval-only object
- into one that is not. For instance, in
- struct B { };
- struct D : B { info r; };
- constexpr D d{^^::};
- constexpr const B &b = d; // #1
- #1 is wrong because D is a consteval-only type but B is not. */
- if (flag_reflection
- && !non_constant_p
- && object
- && POINTER_TYPE_P (TREE_TYPE (object))
- && !consteval_only_p (object)
- && check_out_of_consteval_use (r, /*complain=*/false))
- {
- if (!allow_non_constant)
- {
- if (TYPE_REF_P (TREE_TYPE (object)))
- error_at (cp_expr_loc_or_input_loc (t),
- "reference into an object of consteval-only type is "
- "not a constant expression unless it also has "
- "consteval-only type");
- else
- error_at (cp_expr_loc_or_input_loc (t),
- "pointer into an object of consteval-only type is "
- "not a constant expression unless it also has "
- "consteval-only type");
- }
- r = t;
- non_constant_p = true;
- }
-
if (!non_constant_p && !constexpr_dtor)
verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
@@ -12654,7 +12623,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
return false;
}
}
- return (RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR));
+ /* convert_to_void used to fold these away to void_node, because they
+ are a discarded-value expression. */
+ if (TREE_CODE (t) == CONVERT_EXPR && VOID_TYPE_P (TREE_TYPE (t)))
+ return RECUR (from, /*want_rval=*/false);
+ return RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR);
}
case ADDRESSOF_EXPR:
@@ -2550,7 +2550,10 @@ satisfy_atom (tree t, tree args, sat_info info)
if (info.noisy ())
{
iloc_sentinel ils (EXPR_LOCATION (result));
- result = cxx_constant_value (result);
+ if (require_constant_expression (result))
+ result = cxx_constant_value (result);
+ else
+ result = error_mark_node;
}
else
{
@@ -798,6 +798,13 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
ret = GS_OK;
break;
+ case REFLECT_EXPR:
+ /* Only the null reflection may reach the ME. */
+ gcc_checking_assert (null_reflection_p (*expr_p));
+ rewrite_null_reflection (*expr_p);
+ ret = GS_OK;
+ break;
+
case BASELINK:
*expr_p = BASELINK_FUNCTIONS (*expr_p);
ret = GS_OK;
@@ -861,8 +868,6 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
for (int i = 0; i < call_expr_nargs (*expr_p); ++i)
if (check_out_of_consteval_use (CALL_EXPR_ARG (*expr_p, i)))
ret = GS_ERROR;
- if (consteval_only_p (TREE_TYPE (*expr_p)))
- ret = GS_ERROR;
if (flag_strong_eval_order == 2
&& CALL_EXPR_FN (*expr_p)
&& !CALL_EXPR_OPERATOR_SYNTAX (*expr_p)
@@ -1366,23 +1371,6 @@ cp_build_init_expr_for_ctor (tree call, tree init)
return init;
}
-/* For every DECL_EXPR check if it declares a consteval-only variable and
- if so, overwrite it with a no-op. The point here is not to leak
- consteval-only variables into the middle end. */
-
-static tree
-wipe_consteval_only_r (tree *stmt_p, int *, void *)
-{
- if (TREE_CODE (*stmt_p) == DECL_EXPR)
- {
- tree d = DECL_EXPR_DECL (*stmt_p);
- if (VAR_P (d) && consteval_only_p (d))
- /* Wipe the DECL_EXPR so that it doesn't get into gimple. */
- *stmt_p = void_node;
- }
- return NULL_TREE;
-}
-
/* A walk_tree callback for cp_fold_function and cp_fully_fold_init to handle
immediate functions. */
@@ -1410,17 +1398,6 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_)
return NULL_TREE;
}
- /* Most invalid uses of consteval-only types should have been already
- detected at this point. And the valid ones won't be needed
- anymore. */
- if (flag_reflection
- && complain
- && (data->flags & ff_genericize)
- && TREE_CODE (stmt) == STATEMENT_LIST)
- for (tree s : tsi_range (stmt))
- if (check_out_of_consteval_use (s))
- *stmt_p = void_node;
-
tree decl = NULL_TREE;
bool call_p = false;
@@ -1454,15 +1431,8 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_)
if (IF_STMT_CONSTEVAL_P (stmt))
{
if (!data->pset.add (stmt))
- {
- cp_walk_tree (&ELSE_CLAUSE (stmt), cp_fold_immediate_r, data_,
- nullptr);
- if (flag_reflection)
- /* Check & clear consteval-only DECL_EXPRs even here,
- because we wouldn't be walking this subtree otherwise. */
- cp_walk_tree (&THEN_CLAUSE (stmt), wipe_consteval_only_r,
- data_, nullptr);
- }
+ cp_walk_tree (&ELSE_CLAUSE (stmt), cp_fold_immediate_r, data_,
+ nullptr);
*walk_subtrees = 0;
return NULL_TREE;
}
@@ -1786,6 +1756,56 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
}
break;
+ /* Detect consteval-only values used outside an MCE context. */
+
+ /* A STATEMENT_LIST can be collapsed into one EXPR_STMT. These should be
+ visited before the CONVERT_EXPR below which removes discarded-value
+ expressions. */
+ case RETURN_EXPR:
+ case EXPR_STMT:
+ if (flag_reflection
+ && !cp_unevaluated_operand
+ && (data->flags & (ff_only_non_odr | ff_genericize))
+ && check_out_of_consteval_use (stmt))
+ {
+ if (code == RETURN_EXPR)
+ TREE_OPERAND (stmt, 0) = error_mark_node;
+ else
+ *stmt_p = void_node;
+ }
+ break;
+
+ case STATEMENT_LIST:
+ if (flag_reflection
+ && !cp_unevaluated_operand
+ && (data->flags & (ff_only_non_odr | ff_genericize)))
+ for (tree &s : tsi_range (stmt))
+ if (check_out_of_consteval_use (s))
+ {
+ /* Don't remove the whole BIND_EXPR, just wipe it, for e.g.
+ build_constexpr_constructor_member_initializers's sake. */
+ if (TREE_CODE (s) == BIND_EXPR)
+ BIND_EXPR_BODY (s) = void_node;
+ else
+ s = void_node;
+ }
+ break;
+
+ case CONVERT_EXPR:
+ /* convert_to_void used to fold these away to void_node. Do it now;
+ other code (e.g., trees_out) depends on these being expunged. We
+ do it here before maybe_save_constexpr_fundef copies function
+ bodies. */
+ if ((data->flags & (ff_only_non_odr | ff_genericize))
+ && VOID_TYPE_P (TREE_TYPE (stmt))
+ && !TREE_SIDE_EFFECTS (stmt))
+ {
+ *stmt_p = void_node;
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+ break;
+
default:
break;
}
@@ -2187,17 +2207,12 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
wtd->no_sanitize_p = no_sanitize_p;
}
if (flag_reflection)
- /* Wipe consteval-only vars from BIND_EXPR_VARS and BLOCK_VARS. */
+ /* Adjust consteval-only vars in BIND_EXPR_VARS so that REFLECT_EXPR
+ doesn't leak into the ME. */
for (tree *p = &BIND_EXPR_VARS (stmt); *p; )
{
- if (VAR_P (*p) && consteval_only_p (*p))
- {
- if (BIND_EXPR_BLOCK (stmt)
- && *p == BLOCK_VARS (BIND_EXPR_BLOCK (stmt)))
- BLOCK_VARS (BIND_EXPR_BLOCK (stmt)) = DECL_CHAIN (*p);
- *p = DECL_CHAIN (*p);
- continue;
- }
+ if (VAR_P (*p) && DECL_INITIAL (*p))
+ rewrite_null_reflection (DECL_INITIAL (*p));
p = &DECL_CHAIN (*p);
}
wtd->bind_expr_stack.safe_push (stmt);
@@ -646,7 +646,6 @@ cp_common_init_ts (void)
MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
MARK_TS_TYPE_NON_COMMON (TYPE_PACK_EXPANSION);
MARK_TS_TYPE_NON_COMMON (PACK_INDEX_TYPE);
- MARK_TS_TYPE_NON_COMMON (META_TYPE);
MARK_TS_TYPE_NON_COMMON (SPLICE_SCOPE);
/* Statements. */
@@ -588,9 +588,6 @@ DEFTREECODE (TU_LOCAL_ENTITY, "tu_local_entity", tcc_exceptional, 0)
/* C++26 reflection expression. */
DEFTREECODE (REFLECT_EXPR, "reflect_expr", tcc_expression, 1)
-/* Represents the std::meta::info type. */
-DEFTREECODE (META_TYPE, "meta_type", tcc_type, 0)
-
/* Represents a dependent splice expression. If SPLICE_EXPR_EXPRESSION_P
is set, this tree represents a splice-expression (as opposed to
a splice-specifier). */
@@ -1909,7 +1909,8 @@ struct GTY(()) tree_requires_expr {
(((struct tree_requires_expr *) REQUIRES_EXPR_CHECK (NODE))->loc)
/* True iff TYPE is cv decltype(^^int). */
-#define REFLECTION_TYPE_P(TYPE) (TREE_CODE (TYPE) == META_TYPE)
+#define REFLECTION_TYPE_P(TYPE) \
+ (TYPE_P (TYPE) && TYPE_MAIN_VARIANT (TYPE) == meta_info_type_node)
/* True if NODE is a REFLECT_EXPR. */
#define REFLECT_EXPR_P(NODE) (TREE_CODE (NODE) == REFLECT_EXPR)
@@ -9505,9 +9506,10 @@ extern tree process_metafunction (const constexpr_ctx *, tree, tree,
extern tree get_reflection (location_t, tree, reflect_kind = REFLECT_UNDEF);
extern tree get_null_reflection () ATTRIBUTE_PURE;
extern bool null_reflection_p (const_tree) ATTRIBUTE_PURE;
+extern void rewrite_null_reflection (tree &);
extern tree splice (tree);
extern bool check_out_of_consteval_use (tree, bool = true);
-extern bool consteval_only_p (tree) ATTRIBUTE_PURE;
+extern bool consteval_only_p (tree);
extern bool compare_reflections (tree, tree) ATTRIBUTE_PURE;
extern bool valid_splice_type_p (const_tree) ATTRIBUTE_PURE;
extern bool valid_splice_scope_p (const_tree) ATTRIBUTE_PURE;
@@ -9518,7 +9520,6 @@ extern bool check_splice_expr (location_t, location_t, tree, bool, bool, bool,
extern tree make_splice_scope (tree, bool);
extern bool dependent_splice_p (const_tree) ATTRIBUTE_PURE;
extern tree reflection_mangle_prefix (tree, char [3]);
-extern void check_consteval_only_fn (tree);
extern bool reflection_function_template_p (const_tree) ATTRIBUTE_PURE;
extern void dump_data_member_spec (pretty_printer *, tree);
@@ -1234,14 +1234,6 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
if (concept_check_p (expr) && !cp_unevaluated_operand)
expr = evaluate_concept_check (expr);
- /* Detect using expressions of consteval-only types outside manifestly
- constant-evaluated contexts. We are going to discard this expression,
- so we can't wait till cp_fold_immediate_r. FIXME This is too early;
- code like "int i = (^^i, 42);" is OK. We should stop discarding
- expressions here (PR124249). */
- if (stmts_are_full_exprs_p () && check_out_of_consteval_use (expr))
- return error_mark_node;
-
if (VOID_TYPE_P (TREE_TYPE (expr)))
return expr;
@@ -1741,8 +1733,6 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
}
expr = build1 (CONVERT_EXPR, void_type_node, expr);
}
- if (! TREE_SIDE_EFFECTS (expr))
- expr = void_node;
return expr;
}
@@ -1442,9 +1442,13 @@ cxx_pretty_printer::simple_type_specifier (tree t)
pp_cxx_trait (this, t);
break;
- case META_TYPE:
- pp_cxx_ws_string (this, "std::meta::info");
- break;
+ case LANG_TYPE:
+ if (REFLECTION_TYPE_P (t))
+ {
+ pp_cxx_ws_string (this, "std::meta::info");
+ break;
+ }
+ gcc_fallthrough ();
default:
c_pretty_printer::simple_type_specifier (t);
@@ -1942,7 +1946,6 @@ cxx_pretty_printer::type_id (tree t)
case NULLPTR_TYPE:
case TEMPLATE_ID_EXPR:
case OFFSET_TYPE:
- case META_TYPE:
pp_cxx_type_specifier_seq (this, t);
if (TYPE_PTRMEM_P (t))
abstract_declarator (t);
@@ -1975,6 +1978,14 @@ cxx_pretty_printer::type_id (tree t)
}
break;
+ case LANG_TYPE:
+ if (REFLECTION_TYPE_P (t))
+ {
+ pp_cxx_type_specifier_seq (this, t);
+ break;
+ }
+ gcc_fallthrough ();
+
default:
c_pretty_printer::type_id (t);
break;
@@ -1008,6 +1008,12 @@ wrapup_namespace_globals ()
{
for (tree decl : *statics)
{
+ /* Do this here rather than e.g. in make_rtl_for_nonlocal_decl
+ because that would be too early; we need to keep a null
+ reflection as a REFLECT_EXPR for comparisons etc. */
+ if (flag_reflection && DECL_INITIAL (decl))
+ rewrite_null_reflection (DECL_INITIAL (decl));
+
if (warn_unused_function
&& TREE_CODE (decl) == FUNCTION_DECL
&& DECL_INITIAL (decl) == 0
@@ -10000,10 +10006,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
}
}
- /* Detect stuff like 'info r = ^^int;' outside a manifestly
- constant-evaluated context. */
- check_out_of_consteval_use (decl);
-
/* If this is a local variable that will need a mangled name,
register it now. We must do this before processing the
initializer for the variable, since the initialization might
@@ -10028,10 +10030,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
walk_tree (&init, notice_forced_label_r, NULL, NULL);
add_local_decl (cfun, decl);
}
- if (!consteval_only_p (decl))
- /* And make sure it's in the symbol table for
- c_parse_final_cleanups to find. */
- varpool_node::get_create (decl);
+ /* And make sure it's in the symbol table for
+ c_parse_final_cleanups to find. */
+ varpool_node::get_create (decl);
}
if (flag_openmp
@@ -12893,12 +12894,6 @@ grokfndecl (tree ctype,
if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl))
return NULL_TREE;
- /* Don't call check_consteval_only_fn for defaulted functions. Those are
- immediate-escalating functions but at this point DECL_DEFAULTED_P has
- not been set. */
- if (initialized != SD_DEFAULTED)
- check_consteval_only_fn (decl);
-
if (ctype == NULL_TREE || check)
return decl;
@@ -2662,9 +2662,7 @@ maybe_make_one_only (tree decl)
if (! flag_weak)
return;
- /* These are not to be output. */
- if (consteval_only_p (decl))
- return;
+ gcc_checking_assert (!consteval_only_p (decl));
/* We can't set DECL_COMDAT on functions, or cp_finish_file will think
we can get away with not emitting them if they aren't used. We need
@@ -2822,9 +2820,7 @@ var_finalized_p (tree var)
void
mark_needed (tree decl)
{
- /* These are not to be output. */
- if (consteval_only_p (decl))
- return;
+ gcc_checking_assert (!consteval_only_p (decl));
TREE_USED (decl) = 1;
if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -5050,14 +5046,6 @@ prune_vars_needing_no_initialization (tree *vars)
continue;
}
- /* Reflections are consteval-only types and we don't want them
- to survive until gimplification. */
- if (consteval_only_p (decl))
- {
- var = &TREE_CHAIN (t);
- continue;
- }
-
/* This variable is going to need initialization and/or
finalization, so we add it to the list. */
*var = TREE_CHAIN (t);
@@ -6098,6 +6086,10 @@ c_parse_final_cleanups (void)
/* Static data members are just like namespace-scope globals. */
FOR_EACH_VEC_SAFE_ELT (pending_statics, i, decl)
{
+ /* Rewrite the REFLECT_EXPR with 0 so that the ME can process it. */
+ if (flag_reflection && DECL_INITIAL (decl))
+ rewrite_null_reflection (DECL_INITIAL (decl));
+
if (consteval_only_p (decl)
|| var_finalized_p (decl)
|| DECL_REALLY_EXTERN (decl)
@@ -697,6 +697,11 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
pp_string (pp, M_("<brace-enclosed initializer list>"));
else if (t == unknown_type_node)
pp_string (pp, M_("<unresolved overloaded function type>"));
+ else if (REFLECTION_TYPE_P (t))
+ {
+ pp_cxx_ws_string (pp, "std::meta::info");
+ pp_c_type_qualifier_list (pp, t);
+ }
else
{
pp_cxx_cv_qualifier_seq (pp, t);
@@ -879,11 +884,6 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
pp_c_type_qualifier_list (pp, t);
break;
- case META_TYPE:
- pp_cxx_ws_string (pp, "std::meta::info");
- pp_c_type_qualifier_list (pp, t);
- break;
-
case SPLICE_SCOPE:
dump_expr (pp, SPLICE_SCOPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS);
break;
@@ -1147,7 +1147,6 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags)
case FIXED_POINT_TYPE:
case NULLPTR_TYPE:
case PACK_INDEX_TYPE:
- case META_TYPE:
case SPLICE_SCOPE:
dump_type (pp, t, flags);
pp->set_padding (pp_before);
@@ -1282,7 +1281,6 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
case FIXED_POINT_TYPE:
case NULLPTR_TYPE:
case PACK_INDEX_TYPE:
- case META_TYPE:
case SPLICE_SCOPE:
break;
@@ -3487,7 +3485,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
/* For reflection we care about the difference
between std::meta::info/std::nullptr_t and
decltype(^^int)/decltype(nullptr). */
- if (TREE_CODE (h) == META_TYPE && !typedef_variant_p (h))
+ if (REFLECTION_TYPE_P (h) && !typedef_variant_p (h))
{
pp_cxx_ws_string (pp, "decltype(^^int)");
pp_c_type_qualifier_list (pp, h);
@@ -1008,9 +1008,6 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
if (init == error_mark_node)
return;
- if (check_out_of_consteval_use (init))
- return;
-
/* Effective C++ rule 12 requires that all data members be
initialized. */
if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE)
@@ -2739,11 +2739,6 @@ write_type (tree type)
++is_builtin_type;
break;
- case META_TYPE:
- write_string ("Dm");
- ++is_builtin_type;
- break;
-
case SPLICE_SCOPE:
write_splice (type);
break;
@@ -2776,6 +2771,12 @@ write_type (tree type)
break;
case LANG_TYPE:
+ if (REFLECTION_TYPE_P (type))
+ {
+ write_string ("Dm");
+ ++is_builtin_type;
+ break;
+ }
/* fall through. */
default:
@@ -9889,8 +9889,9 @@ trees_out::type_node (tree type)
}
break;
- case META_TYPE:
+ case LANG_TYPE:
/* No additional data. */
+ gcc_checking_assert (REFLECTION_TYPE_P (type));
break;
case SPLICE_SCOPE:
@@ -10744,7 +10745,10 @@ trees_in::tree_node (bool is_use)
}
break;
- case META_TYPE:
+ /* LANG_TYPE can be more things, but here we assume it represents
+ std::meta::info. Unfortunately here it's not possible to check
+ REFLECTION_TYPE_P. */
+ case LANG_TYPE:
if (!get_overrun ())
res = meta_info_type_node;
break;
@@ -1570,13 +1570,6 @@ name_lookup::adl_type (tree type)
adl_type (TYPE_PTRMEM_POINTED_TO_TYPE (type));
return;
}
- else if (REFLECTION_TYPE_P (type))
- {
- /* The namespace std::meta is an associated namespace of
- std::meta::info. */
- adl_namespace (std_meta_node);
- return;
- }
switch (TREE_CODE (type))
{
@@ -1611,6 +1604,13 @@ name_lookup::adl_type (tree type)
return;
case LANG_TYPE:
+ if (REFLECTION_TYPE_P (type))
+ {
+ /* The namespace std::meta is an associated namespace of
+ std::meta::info. */
+ adl_namespace (std_meta_node);
+ return;
+ }
gcc_assert (type == unknown_type_node
|| type == init_list_type_node);
return;
@@ -17395,7 +17395,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case VECTOR_TYPE:
case BOOLEAN_TYPE:
case NULLPTR_TYPE:
- case META_TYPE:
case LANG_TYPE:
return t;
@@ -26865,7 +26864,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
case VOID_TYPE:
case OPAQUE_TYPE:
case NULLPTR_TYPE:
- case META_TYPE:
+ case LANG_TYPE:
if (TREE_CODE (arg) != TREE_CODE (parm))
return unify_type_mismatch (explain_p, parm, arg);
@@ -29011,8 +29010,6 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p)
if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
cp_check_omp_declare_reduction (d);
- check_consteval_only_fn (d);
-
if (int errs = errorcount + sorrycount)
if (errs > current_tinst_level->errors)
if (function *f = DECL_STRUCT_FUNCTION (d))
@@ -61,7 +61,7 @@ init_reflection ()
/* The type std::meta::info is a scalar type for which equality and
inequality are meaningful, but for which no ordering relation is
defined. */
- meta_info_type_node = make_node (META_TYPE);
+ meta_info_type_node = make_node (LANG_TYPE);
/* Make it a complete type. */
TYPE_SIZE (meta_info_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode));
TYPE_SIZE_UNIT (meta_info_type_node) = size_int (GET_MODE_SIZE (ptr_mode));
@@ -291,8 +291,36 @@ get_null_reflection ()
bool
null_reflection_p (const_tree t)
{
- return (t && TREE_CODE (t) == REFLECT_EXPR
- && REFLECT_EXPR_HANDLE (t) == unknown_type_node);
+ if (!t)
+ return false;
+
+ if (REFLECT_EXPR_P (t) && REFLECT_EXPR_HANDLE (t) == unknown_type_node)
+ return true;
+
+ /* This is the rewritten form. */
+ return integer_zerop (t) && REFLECTION_TYPE_P (TREE_TYPE (t));
+}
+
+/* If R represents a null reflection, rewrite it with something the ME
+ can process; that is, something that doesn't use REFLECT_EXPR. */
+
+void
+rewrite_null_reflection (tree &r)
+{
+ /* A tree walk mostly only so that we recurse through CONSTRUCTORs. */
+ auto walker = [](tree *tp, int *walk_subtrees, void *) -> tree
+ {
+ if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+ else if (null_reflection_p (*tp))
+ {
+ *tp = build_int_cst (meta_info_type_node, 0);
+ *walk_subtrees = 0;
+ }
+ return NULL_TREE;
+ };
+
+ cp_walk_tree (&r, walker, nullptr, nullptr);
}
/* Do strip_typedefs on T, but only for types. */
@@ -8803,153 +8831,116 @@ splice (tree refl)
return refl;
}
-/* A cache of the known boolean result of consteval_only_p_walker::walk
- for class types. */
+static bool consteval_only_p (tree, hash_set<tree> &);
+
+/* True if T is a consteval-only value as per [expr.const.const]/1:
+ A consteval-only value is either
+ -- a reflection value that is not the null reflection value or
+ -- a pointer or pointer-to-member that points to an immediate function
+ or to or past the end of an immediate object.
-static GTY((cache)) type_tree_cache_map *consteval_only_class_cache;
+ This function doesn't look for an immediate function; for that, see
+ find_immediate_fndecl. */
-struct consteval_only_p_walker
+static bool
+consteval_only_value_p (tree t, hash_set<tree> &seen)
{
- /* The set of class types we've seen. */
- hash_set<tree> class_seen;
- /* The number of class types we're recursively inside. */
- int class_depth = 0;
- /* True if we've optimistically assumed an already-seen
- consteval-unknown class type is not consteval. */
- bool optimistic_p = false;
+ STRIP_NOPS (t);
- tristate walk (tree);
-};
+ if (REFLECT_EXPR_P (t) && !null_reflection_p (t))
+ return true;
-/* True if T is a consteval-only type as per [basic.types.general]/12,
- or is a declaration with such a type, or a TREE_VEC thereof. */
+ switch (TREE_CODE (t))
+ {
+ case ADDR_EXPR:
+ case POINTER_PLUS_EXPR:
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ return consteval_only_p (TREE_OPERAND (t, 0), seen);
+ default:
+ break;
+ }
+ return false;
+}
-bool
-consteval_only_p (tree t)
+/* Return true if T is an immediate object as per [expr.const.const]/2:
+ An object is an immediate object if its complete object has
+ -- a constituent value that is consteval-only or
+ -- a constituent reference that refers to an immediate object or
+ immediate function.
+
+ Also return true for consteval-only values. This doesn't check for
+ immediate functions. */
+
+static bool
+consteval_only_p (tree t, hash_set<tree> &seen)
{
- if (!flag_reflection)
+ if (!flag_reflection || !t || t == error_mark_node)
return false;
- if (!TYPE_P (t))
- t = TREE_TYPE (t);
+ /* Say that the wrapper itself is consteval-only so that
+ check_out_of_consteval_use_r returns the tree carrying the location. */
+ STRIP_ANY_LOCATION_WRAPPER (t);
- if (!t || t == error_mark_node)
+ /* Walking COMPONENT_REFs can walk back into a CONSTRUCTOR that's still
+ under construction and we'd loop. */
+ if (seen.add (t))
return false;
if (TREE_CODE (t) == TREE_VEC)
{
for (tree arg : tree_vec_range (t))
- if (arg && consteval_only_p (arg))
+ if (arg && consteval_only_p (arg, seen))
return true;
return false;
}
- /* For dependent types we can't be sure if this type is consteval-only. */
- if (dependent_type_p (t))
- return false;
-
- consteval_only_p_walker walker;
- return walker.walk (t).is_true ();
-}
-
-/* Recursive workhorse of consteval_only_p. Returns true if T is definitely
- consteval-only, false if it's definitely not, and unknown if we saw an
- incomplete type and therefore don't know. */
-
-tristate
-consteval_only_p_walker::walk (tree t)
-{
- if (t == error_mark_node)
- return false;
+ /* Pull out the initializer. Don't call fold_non_dependent_expr and
+ similar here because that could prematurely instantiate things. */
+ if (VAR_P (t))
+ t = DECL_INITIAL (t);
- t = TYPE_MAIN_VARIANT (t);
+ if (t && TREE_CODE (t) == TARGET_EXPR)
+ t = TARGET_EXPR_INITIAL (t);
- if (REFLECTION_TYPE_P (t))
- return true;
- else if (INDIRECT_TYPE_P (t))
- return walk (TREE_TYPE (t));
- else if (TREE_CODE (t) == ARRAY_TYPE)
- return walk (TREE_TYPE (t));
- else if (FUNC_OR_METHOD_TYPE_P (t))
- {
- tristate r = walk (TREE_TYPE (t));
- for (tree parm = TYPE_ARG_TYPES (t);
- parm != NULL_TREE && parm != void_list_node;
- parm = TREE_CHAIN (parm))
- {
- if (r.is_true ())
- break;
- r = r || walk (TREE_VALUE (parm));
- }
- return r;
- }
- else if (RECORD_OR_UNION_TYPE_P (t))
+ if (t && TREE_CODE (t) == CONSTRUCTOR)
{
- if (tree *slot = hash_map_safe_get (consteval_only_class_cache, t))
- return *slot == boolean_true_node;
-
- if (!COMPLETE_TYPE_P (t) && LAMBDA_TYPE_P (t))
- /* Defer until we've definitely gone through prune_lambda_captures. */
- return tristate::unknown ();
+ for (constructor_elt &elt : CONSTRUCTOR_ELTS (t))
+ if (consteval_only_p (elt.value, seen))
+ return true;
+ return false;
+ }
- if (class_seen.add (t))
- {
- /* Optimistically assume this already seen consteval-unknown class is
- not consteval-only, for sake of mutually recursive classes. */
- optimistic_p = true;
- return false;
- }
- ++class_depth;
+ return t && consteval_only_value_p (t, seen);
+}
- tristate r = COMPLETE_TYPE_P (t) ? false : tristate::unknown ();
- for (tree member = TYPE_FIELDS (t); member; member = DECL_CHAIN (member))
- if (TREE_CODE (member) == FIELD_DECL)
- {
- r = r || walk (TREE_TYPE (member));
- if (r.is_true ())
- break;
- }
+/* Wrapper for consteval_only_p that sets up a hash set. */
- if (r.is_true ())
- hash_map_safe_put<hm_ggc> (consteval_only_class_cache,
- t, boolean_true_node);
- else if (r.is_false ()
- /* The optimistic assumption above is at odds with caching
- 'false' results for a nested class type. */
- && (class_depth == 1 || !optimistic_p))
- hash_map_safe_put<hm_ggc> (consteval_only_class_cache,
- t, boolean_false_node);
-
- --class_depth;
- return r;
- }
- else if (TYPE_PTRMEM_P (t))
- return (walk (TYPE_PTRMEM_CLASS_TYPE (t))
- || walk (TYPE_PTRMEM_POINTED_TO_TYPE (t)));
- else
- return false;
+bool
+consteval_only_p (tree t)
+{
+ hash_set<tree> seen;
+ return consteval_only_p (t, seen);
}
/* A walker for check_out_of_consteval_use_r. It cannot be a lambda, because
we have to call this recursively. */
static tree
-check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset)
+check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset_)
{
tree t = *tp;
+ auto pset = static_cast<hash_set<tree> *>(pset_);
/* No need to look into types or unevaluated operands. */
if (TYPE_P (t)
|| (unevaluated_p (TREE_CODE (t)) && !REFLECT_EXPR_P (t))
- /* Don't walk INIT_EXPRs, because we'd emit bogus errors about
- member initializers. */
- || TREE_CODE (t) == INIT_EXPR
- /* And don't recurse on DECL_EXPRs. */
+ /* Don't recurse on DECL_EXPRs. */
|| TREE_CODE (t) == DECL_EXPR
/* Neither into USING_STMT. */
|| TREE_CODE (t) == USING_STMT
/* The operand of a splice is a constant-expression, thus
- manifestly constant-evaluated, so consteval-only types are permitted
+ manifestly constant-evaluated, so consteval-only values are permitted
here. */
|| TREE_CODE (t) == SPLICE_EXPR
/* Blocks can appear in the TREE_VEC operand of OpenMP
@@ -8974,19 +8965,33 @@ check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset)
return NULL_TREE;
}
+ if (TREE_CODE (t) == EXPR_STMT)
+ {
+ if (tree r = cp_walk_tree (&EXPR_STMT_EXPR (t),
+ check_out_of_consteval_use_r, pset, pset))
+ {
+ /* If we can't give a precise location of the expression,
+ use the location of the whole statement. */
+ if (cp_expr_location (r) == UNKNOWN_LOCATION)
+ return t;
+ return r;
+ }
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
+
if (VAR_P (t) && DECL_HAS_VALUE_EXPR_P (t))
{
tree vexpr = DECL_VALUE_EXPR (t);
if (tree ret = cp_walk_tree (&vexpr, check_out_of_consteval_use_r, pset,
- (hash_set<tree> *) pset))
+ pset))
return ret;
}
if (TREE_CODE (t) == BIND_EXPR)
{
if (tree r = cp_walk_tree (&BIND_EXPR_BODY (t),
- check_out_of_consteval_use_r, pset,
- static_cast<hash_set<tree> *>(pset)))
+ check_out_of_consteval_use_r, pset, pset))
return r;
/* Don't walk BIND_EXPR_VARS. */
*walk_subtrees = false;
@@ -8998,8 +9003,7 @@ check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset)
if (IF_STMT_CONSTEVAL_P (t))
{
if (tree r = cp_walk_tree (&ELSE_CLAUSE (t),
- check_out_of_consteval_use_r, pset,
- static_cast<hash_set<tree> *>(pset)))
+ check_out_of_consteval_use_r, pset, pset))
return r;
/* Don't walk the consteval branch. */
*walk_subtrees = false;
@@ -9008,12 +9012,10 @@ check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset)
else if (IF_STMT_CONSTEXPR_P (t))
{
if (tree r = cp_walk_tree (&THEN_CLAUSE (t),
- check_out_of_consteval_use_r, pset,
- static_cast<hash_set<tree> *>(pset)))
+ check_out_of_consteval_use_r, pset, pset))
return r;
if (tree r = cp_walk_tree (&ELSE_CLAUSE (t),
- check_out_of_consteval_use_r, pset,
- static_cast<hash_set<tree> *>(pset)))
+ check_out_of_consteval_use_r, pset, pset))
return r;
/* Don't walk the condition -- it's a manifestly constant-evaluated
context. */
@@ -9033,8 +9035,7 @@ check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset)
return NULL_TREE;
}
- /* Now check the type to see if we are dealing with a consteval-only
- expression. */
+ /* If we don't find an immediate object, there's nothing to do. */
if (!consteval_only_p (t))
return NULL_TREE;
@@ -9061,7 +9062,15 @@ check_out_of_consteval_use_r (tree *tp, int *walk_subtrees, void *pset)
/* Detect if a consteval-only expression EXPR or a consteval-only
variable EXPR not declared constexpr is used outside
- a manifestly constant-evaluated context. E.g.:
+ a manifestly constant-evaluated context.
+
+ [expr.const.const]/3: Every immediate object shall be
+ -- the object associated with a constexpr variable or a subobject thereof,
+ -- a template parameter object ([temp.param]) or a subject thereof, or
+ -- an object whose lifetime begins and ends during the evaluation of
+ a core constant expression.
+
+ E.g.:
void f() {
constexpr auto r = ^^int; // OK
@@ -9092,20 +9101,9 @@ check_out_of_consteval_use (tree expr, bool complain/*=true*/)
if (tree t = cp_walk_tree (&expr, check_out_of_consteval_use_r, &pset, &pset))
{
if (complain)
- {
- if (VAR_P (t) && !DECL_DECLARED_CONSTEXPR_P (t))
- {
- auto_diagnostic_group d;
- error_at (cp_expr_loc_or_input_loc (t),
- "consteval-only variable %qD not declared %<constexpr%> "
- "used outside a constant-evaluated context", t);
- inform (DECL_SOURCE_LOCATION (t), "add %<constexpr%>");
- }
- else
- error_at (cp_expr_loc_or_input_loc (t),
- "consteval-only expressions are only allowed in "
- "a constant-evaluated context");
- }
+ error_at (cp_expr_loc_or_input_loc (t),
+ "consteval-only value outside an immediate function "
+ "context");
return true;
}
@@ -9238,21 +9236,6 @@ valid_splice_for_member_access_p (const_tree t, bool decls_only_p/*=true*/)
|| TREE_CODE (t) == TREE_BINFO);
}
-/* Check a function DECL for CWG 3115: Every function of consteval-only
- type shall be an immediate function. */
-
-void
-check_consteval_only_fn (tree decl)
-{
- if (!DECL_IMMEDIATE_FUNCTION_P (decl)
- && consteval_only_p (decl)
- /* But if the function can be escalated, merrily we roll along. */
- && !immediate_escalating_function_p (decl))
- error_at (DECL_SOURCE_LOCATION (decl),
- "function of consteval-only type must be declared %qs",
- "consteval");
-}
-
/* Check if T is a valid result of splice-expression. ADDRESS_P is true if
we are taking the address of the splice. MEMBER_ACCESS_P is true if this
splice is used in foo.[: bar :] or foo->[: bar :] context. TEMPLATE_P is
@@ -2131,15 +2131,13 @@ check_final_overrider (tree overrider, tree basefn)
return 0;
}
- /* A class with a consteval virtual function that overrides a virtual
- function that is not consteval shall have consteval-only type (CWG 3117).
- A consteval virtual function shall not be overridden by a virtual
- function that is not consteval. */
+ /* [class.virtual]/18: A non-immediate virtual function shall not be
+ overridden by an immediate virtual function. An immediate virtual
+ function shall not be overridden by a non-immediate virtual function. */
if ((DECL_IMMEDIATE_FUNCTION_P (basefn)
&& !DECL_IMMEDIATE_FUNCTION_P (overrider))
|| (!DECL_IMMEDIATE_FUNCTION_P (basefn)
- && DECL_IMMEDIATE_FUNCTION_P (overrider)
- && !consteval_only_p (overrider)))
+ && DECL_IMMEDIATE_FUNCTION_P (overrider)))
{
auto_diagnostic_group d;
if (DECL_IMMEDIATE_FUNCTION_P (overrider))
@@ -15007,12 +15007,6 @@ cp_build_bit_cast (location_t loc, tree type, tree arg,
"is not trivially copyable", type);
return error_mark_node;
}
- if (consteval_only_p (type) || consteval_only_p (arg))
- {
- error_at (loc, "%<__builtin_bit_cast%> cannot be used with "
- "consteval-only types");
- return error_mark_node;
- }
}
if (error_operand_p (arg))
@@ -5174,6 +5174,16 @@ type_has_unique_obj_representations (const_tree t, bool explain/*=false*/)
inform (loc, "%<std::nullptr_t%> has padding bits and no value bits");
return false;
+ case LANG_TYPE:
+ if (REFLECTION_TYPE_P (t))
+ {
+ if (explain)
+ inform (loc, "%<std::meta::info%> has an unspecified object "
+ "representation");
+ return false;
+ }
+ gcc_fallthrough ();
+
default:
gcc_unreachable ();
}
@@ -6389,7 +6389,7 @@ cp_build_binary_op (const op_location_t &location,
}
/* [expr.eq]: "If both operands are of type std::meta::info,
comparison is defined as follows..." */
- else if (code0 == META_TYPE && code1 == META_TYPE)
+ else if (REFLECTION_TYPE_P (type0) && REFLECTION_TYPE_P (type1))
result_type = type0;
else
{
@@ -11901,12 +11901,6 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
*dangling = true;
}
- if (check_out_of_consteval_use (retval))
- {
- current_function_return_value = error_mark_node;
- return error_mark_node;
- }
-
/* A naive attempt to reduce the number of -Wdangling-reference false
positives: if we know that this function can return a variable with
static storage duration rather than one of its parameters, suppress
@@ -1136,6 +1136,42 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
/* Handle aggregate NSDMI in non-constant initializers, too. */
value = replace_placeholders (value, decl);
+ /* Detect stuff like 'info r = ^^int;' outside a manifestly
+ constant-evaluated context. */
+ if (flag_reflection
+ && !processing_template_decl
+ && !DECL_DECLARED_CONSTEXPR_P (decl))
+ {
+ const bool mce_p
+ = (decl_maybe_constant_var_p (decl)
+ || (TREE_STATIC (decl)
+ && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)));
+ bool bad = check_out_of_consteval_use (value, /*complain=*/false);
+ /* A non-constexpr variable at namespace scope with a constant
+ initializer has constant initialization, so we check the folded
+ value not to wrongly reject "int e = (^^int, 42);". For non-static
+ local variables, there is no such rule, so we check the unfolded
+ initializer. But we should also reject
+
+ consteval auto fn () { return ^^int; }
+ void g() { auto r = fn (); }
+
+ so we may have to check both. Note that the first call could
+ have escalated and so we may find ourselves in an immediate
+ context now. */
+ if (!bad && !mce_p && value != init)
+ bad = check_out_of_consteval_use (init, /*complain=*/false);
+ if (bad)
+ {
+ auto_diagnostic_group d;
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qD is initialized with a consteval-only value but is "
+ "not declared %<constexpr%>", decl);
+ inform (DECL_SOURCE_LOCATION (decl), "add %<constexpr%>");
+ value = error_mark_node;
+ }
+ }
+
/* A COMPOUND_LITERAL_P CONSTRUCTOR is the syntactic form; by the time we get
here it should have been digested into an actual value for the type. */
gcc_checking_assert (TREE_CODE (value) != CONSTRUCTOR
@@ -7138,6 +7138,8 @@ count_type_elements (const_tree type, bool for_ctor_p)
case POINTER_TYPE:
case OFFSET_TYPE:
case REFERENCE_TYPE:
+ /* This could represent the C++ std::meta::info type. */
+ case LANG_TYPE:
case NULLPTR_TYPE:
case OPAQUE_TYPE:
case BITINT_TYPE:
@@ -7149,7 +7151,6 @@ count_type_elements (const_tree type, bool for_ctor_p)
case VOID_TYPE:
case METHOD_TYPE:
case FUNCTION_TYPE:
- case LANG_TYPE:
default:
gcc_unreachable ();
}
@@ -6,4 +6,4 @@ struct A {
void f() requires (this, true) { }
};
-template struct A<int>;
+template struct A<int>; // { dg-error ".this. is not a constant expression" }
@@ -10,10 +10,20 @@ f ()
auto a = ^^int;
auto *b = &a;
void *c = nullptr;
- (void) std::bit_cast<void *>(b); // { dg-message "from here" }
- (void) std::bit_cast<decltype(^^int) *>(c); // { dg-message "from here" }
- __builtin_bit_cast (void *, b); // { dg-error ".__builtin_bit_cast. cannot be used with consteval-only types" }
- __builtin_bit_cast (decltype(^^int) *, c); // { dg-error ".__builtin_bit_cast. cannot be used with consteval-only types" }
+ (void) std::bit_cast<void *>(b);
+ (void) std::bit_cast<decltype(^^int) *>(c);
+ __builtin_bit_cast (void *, b);
+ __builtin_bit_cast (decltype(^^int) *, c);
}
-// { dg-error ".__builtin_bit_cast. cannot be used with consteval-only types" "" { target *-*-* } 0 }
+void
+g ()
+{
+ constexpr static auto a = ^^int;
+ constexpr auto *b = &a;
+ void *c = nullptr;
+ (void) std::bit_cast<void *>(b); // { dg-error "consteval-only value outside an immediate function context" }
+ (void) std::bit_cast<decltype(^^int) *>(c);
+ __builtin_bit_cast (void *, b); // { dg-error "consteval-only value outside an immediate function context" }
+ __builtin_bit_cast (decltype(^^int) *, c);
+}
new file mode 100644
@@ -0,0 +1,12 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+/* I don't know what these should actually do. At least make sure we don't
+ ICE. */
+constexpr auto x = __builtin_bit_cast (unsigned long, ^^int); // { dg-message "sorry, unimplemented: .__builtin_bit_cast. cannot be constant evaluated because the argument cannot be encoded" }
+constexpr auto y = __builtin_bit_cast (decltype(^^int), 0UL); // { dg-message "sorry, unimplemented: .__builtin_bit_cast. cannot be constant evaluated because the argument cannot be interpreted" }
+info z = __builtin_bit_cast (decltype(^^int), 0xdeadbeefUL);
@@ -3,6 +3,6 @@
#include <meta>
-struct X { constexpr operator std::meta::info(); }; // { dg-error "function of consteval-only type" }
+struct X { constexpr operator std::meta::info(); };
// { dg-warning "used but never defined" "" { target *-*-* } .-1 }
constexpr auto r = std::meta::type_of (X{}); // { dg-error "used before its definition" }
@@ -3,4 +3,4 @@
// We also test this elsewhere but we only crashed when there were no other
// errors.
-void fn (decltype(^^::)) {} // { dg-error "function of consteval-only type must be declared .consteval." }
+void fn (decltype(^^::)) {}
@@ -2,31 +2,31 @@
// { dg-additional-options "-freflection" }
// Test that we suggest adding "constexpr" (where allowed).
-auto foo = ^^int; // { dg-error "consteval-only variable .foo." }
+auto foo = ^^int; // { dg-error ".foo. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
-constinit auto foo_ = ^^int; // { dg-error "consteval-only variable .foo_." }
+constinit auto foo_ = ^^int; // { dg-error ".foo_. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
constexpr auto foo__ = ^^int;
-thread_local auto tfoo = ^^int; // { dg-error "consteval-only variable .tfoo." }
+thread_local auto tfoo = ^^int; // { dg-error ".tfoo. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
-thread_local constinit auto tfoo_ = ^^int; // { dg-error "consteval-only variable .tfoo_." }
+thread_local constinit auto tfoo_ = ^^int; // { dg-error ".tfoo_. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
thread_local constexpr auto tfoo__ = ^^int;
void
f ()
{
- auto ref = ^^int; // { dg-error "consteval-only variable .ref." }
+ auto ref = ^^int; // { dg-error ".ref. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
constexpr auto ref_ = ^^int;
- static auto sref = ^^int; // { dg-error "consteval-only variable .sref." }
+ static auto sref = ^^int; // { dg-error ".sref. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
- static auto constinit sref_ = ^^int; // { dg-error "consteval-only variable .sref_." }
+ static auto constinit sref_ = ^^int; // { dg-error ".sref_. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
static auto constexpr sref__ = ^^int;
- thread_local auto tref = ^^int; // { dg-error "consteval-only variable .tref." }
+ thread_local auto tref = ^^int; // { dg-error ".tref. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
- thread_local constinit auto tref_ = ^^int; // { dg-error "consteval-only variable .tref_." }
+ thread_local constinit auto tref_ = ^^int; // { dg-error ".tref_. is initialized with a consteval-only value" }
// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
thread_local constexpr auto tref__ = ^^int;
}
@@ -11,18 +11,18 @@ f ()
constexpr auto q = ^^float;
if constexpr (foo (^^::) == ^^::)
{
- auto r = ^^int; // { dg-error "consteval-only variable .r." }
+ auto r = ^^int; // { dg-error "consteval-only value" }
constexpr auto cr = ^^int;
}
- if constexpr (auto r = ^^int; // { dg-error "consteval-only variable .r." }
+ if constexpr (auto r = ^^int; // { dg-error "consteval-only value" }
r == ^^int); // { dg-error "the value of .r. is not usable" }
if constexpr (constexpr auto r = ^^int; r == ^^int);
if constexpr (q != ^^char);
if constexpr (^^int != ^^char);
- if (q != ^^char); // { dg-error "consteval-only expressions" }
- if (^^char == ^^char); // { dg-error "consteval-only expressions" }
- while (^^char == ^^char); // { dg-error "consteval-only expressions" }
- do {} while (^^char == ^^char); // { dg-error "consteval-only expressions" }
+ if (q != ^^char); // { dg-error "consteval-only value" }
+ if (^^char == ^^char); // { dg-error "consteval-only value" }
+ while (^^char == ^^char); // { dg-error "consteval-only value" }
+ do {} while (^^char == ^^char); // { dg-error "consteval-only value" }
consteval {
if (q != ^^char);
if (^^char == ^^char);
@@ -32,18 +32,18 @@ f ()
if constexpr (true)
{
- auto r = ^^int; // { dg-error "consteval-only variable .r." }
+ auto r = ^^int; // { dg-error "consteval-only value" }
}
else
{
- auto r = ^^int; // { dg-error "consteval-only variable .r." }
+ auto r = ^^int; // { dg-error "consteval-only value" }
}
if constexpr (false)
{
- auto r = ^^int; // { dg-error "consteval-only variable .r." }
+ auto r = ^^int; // { dg-error "consteval-only value" }
}
else
{
- auto r = ^^int; // { dg-error "consteval-only variable .r." }
+ auto r = ^^int; // { dg-error "consteval-only value" }
}
}
@@ -19,30 +19,30 @@ f ()
if not consteval
{
- ^^void; // { dg-error "consteval-only expressions" }
+ ^^void; // { dg-error "consteval-only value" }
}
if not consteval
{
- q; // { dg-error "consteval-only expressions" }
+ q; // { dg-error "consteval-only value" }
}
if not consteval
{
- auto r = ^^int; // { dg-error "consteval-only variable" }
+ auto r = ^^int; // { dg-error "consteval-only value" }
}
if not consteval
{
- if (q != ^^char); // { dg-error "consteval-only expressions" }
+ if (q != ^^char); // { dg-error "consteval-only value" }
}
if not consteval
{
- if (^^char == ^^char); // { dg-error "consteval-only expressions" }
+ if (^^char == ^^char); // { dg-error "consteval-only value" }
}
if not consteval
{
- while (^^char != ^^char); // { dg-error "consteval-only expressions" }
+ while (^^char != ^^char); // { dg-error "consteval-only value" }
}
if not consteval
{
- do {} while (^^char != ^^char); // { dg-error "consteval-only expressions" }
+ do {} while (^^char != ^^char); // { dg-error "consteval-only value" }
}
}
new file mode 100644
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+constexpr auto r = ^^int;
+
+void f () { (void) r; } // { dg-error "consteval-only" }
+void g (bool c) { if (c) (void) r; } // { dg-error "consteval-only" }
+auto h () { return r; } // { dg-error "consteval-only" }
@@ -9,8 +9,8 @@ struct A {
consteval A() : i{^^void} {}
};
-A a1; // { dg-error "consteval-only variable .a1." }
-constinit A a2; // { dg-error "consteval-only variable .a2." }
+A a1; // { dg-error "consteval-only value" }
+constinit A a2; // { dg-error "consteval-only value" }
constexpr A a3;
struct B {
@@ -19,6 +19,6 @@ struct B {
consteval B() : i{}, j{i} {}
};
-B b1; // { dg-error "consteval-only variable .b1." }
-constinit B b2; // { dg-error "consteval-only variable .b2." }
+B b1;
+constinit B b2;
constexpr B b3;
@@ -1,6 +1,5 @@
// { dg-do compile { target c++26 } }
// { dg-additional-options "-freflection" }
-// Test invalid reflections in member init lists.
using info = decltype(^^void);
@@ -16,10 +15,10 @@ struct B {
struct C {
info i;
- constexpr C() : i{} {} // { dg-error "function of consteval-only type must be declared .consteval." }
+ constexpr C() : i{} {}
};
struct D {
info i;
- D() : i{} {} // { dg-error "function of consteval-only type must be declared .consteval." }
+ D() : i{} {}
};
@@ -24,6 +24,6 @@ void
g ()
{
constexpr static auto r = ^^int;
- constexpr auto x = foo<info>(&r); // { dg-error "pointer into an object of consteval-only type" }
+ constexpr auto x = foo<info>(&r);
constexpr auto y = bar<info>(nullptr);
}
@@ -41,7 +41,7 @@ void fox() {
do_something_runtime<A>();
int C = something_of(A);
constexpr int E = something_of(A);
- identity(A); // { dg-error "consteval-only expressions" }
- identity(B); // { dg-error "consteval-only expressions" }
+ identity(A); // { dg-error "consteval-only value" }
+ identity(B); // { dg-error "consteval-only value" }
}
}
@@ -8,5 +8,5 @@ struct N { int i; };
template<typename T>
struct X : T { };
-auto a = X<C>{}; // { dg-error "outside a constant-evaluated context" }
+auto a = X<C>{};
auto b = X<N>{};
@@ -49,7 +49,7 @@ constexpr G g;
struct H {
info (*fp)();
};
-constexpr H h{foo}; // { dg-error "address of immediate function" }
+constexpr H h{foo}; // { dg-bogus "returns address" "" { xfail *-*-* } }
union U {
int n;
@@ -12,10 +12,10 @@ consteval const Base &fn1() {
static constexpr Derived d;
return d;
}
-constexpr auto &ref = fn1(); // { dg-error "reference into an object of consteval-only type" }
+constexpr auto &ref = fn1();
consteval void *fn2() {
static constexpr auto v = ^^int;
return (void *)&v;
}
-constexpr const void *ptr = fn2(); // { dg-error "pointer into an object of consteval-only type" }
+constexpr const void *ptr = fn2();
@@ -11,12 +11,12 @@ struct N {
info i = ^^void;
};
-S s1; // { dg-error "consteval-only variable" }
-constinit S s2{}; // { dg-error "consteval-only variable" }
+S s1;
+constinit S s2{};
constexpr S s3{^^int};
-N n1; // { dg-error "consteval-only variable" }
-constinit N n2; // { dg-error "consteval-only variable" }
+N n1; // { dg-error "consteval-only value" }
+constinit N n2; // { dg-error "consteval-only value" }
constexpr N n3;
template<typename T>
@@ -24,8 +24,8 @@ struct X {
T t;
};
-X<info> x1; // { dg-error "consteval-only variable" }
-constinit X<info> x2{}; // { dg-error "consteval-only variable" }
+X<info> x1;
+constinit X<info> x2{};
constexpr X<info> x3{^^int};
void
@@ -5,25 +5,25 @@
using info = decltype(^^int);
-info r1 = ^^int; // { dg-error "consteval-only variable .r1. not declared .constexpr. used outside a constant-evaluated context" }
-const info r2 = ^^int; // { dg-error "consteval-only variable .r2. not declared .constexpr. used outside a constant-evaluated context" }
+info r1 = ^^int; // { dg-error ".r1. is initialized with a consteval-only value but is not declared .constexpr." }
+const info r2 = ^^int; // { dg-error ".r2. is initialized with a consteval-only value but is not declared .constexpr." }
constexpr info r3 = ^^int;
-constinit info r4 = ^^int; // { dg-error "consteval-only variable .r4. not declared .constexpr. used outside a constant-evaluated context" }
-const info *const p1 = &r3; // { dg-error "consteval-only variable .p1. not declared .constexpr. used outside a constant-evaluated context" }
-info *p2; // { dg-error "consteval-only variable .p2. not declared .constexpr. used outside a constant-evaluated context" }
-const info &q = r3; // { dg-error "consteval-only variable .q. not declared .constexpr. used outside a constant-evaluated context" }
+constinit info r4 = ^^int; // { dg-error ".r4. is initialized with a consteval-only value but is not declared .constexpr." }
+const info *const p1 = &r3; // { dg-error ".p1. is initialized with a consteval-only value but is not declared .constexpr." }
+info *p2;
+const info &q = r3; // { dg-error ".q. is initialized with a consteval-only value but is not declared .constexpr." }
void
g ()
{
- info l1 = ^^int; // { dg-error "consteval-only variable .l1. not declared .constexpr. used outside a constant-evaluated context" }
- const info l2 = ^^int; // { dg-error "consteval-only variable .l2. not declared .constexpr. used outside a constant-evaluated context" }
+ info l1 = ^^int; // { dg-error ".l1. is initialized with a consteval-only value but is not declared .constexpr." }
+ const info l2 = ^^int; // { dg-error ".l2. is initialized with a consteval-only value but is not declared .constexpr." }
constexpr info l3 = ^^int;
- static info l4 = ^^int; // { dg-error "consteval-only variable .l4. not declared .constexpr. used outside a constant-evaluated context" }
- static const info l5 = ^^int; // { dg-error "consteval-only variable .l5. not declared .constexpr. used outside a constant-evaluated context" }
+ static info l4 = ^^int; // { dg-error ".l4. is initialized with a consteval-only value but is not declared .constexpr." }
+ static const info l5 = ^^int; // { dg-error ".l5. is initialized with a consteval-only value but is not declared .constexpr." }
static constexpr info l6 = ^^int;
- static constinit info l7 = ^^int; // { dg-error "consteval-only variable .l7. not declared .constexpr. used outside a constant-evaluated context" }
+ static constinit info l7 = ^^int; // { dg-error ".l7. is initialized with a consteval-only value but is not declared .constexpr." }
}
consteval void
@@ -4,9 +4,9 @@
using info = decltype(^^int);
-info foo (); // { dg-error "function of consteval-only type must be declared .consteval." }
-constexpr info bar (); // { dg-error "function of consteval-only type must be declared .consteval." }
-void baz (info); // { dg-error "function of consteval-only type must be declared .consteval." }
+info foo ();
+constexpr info bar ();
+void baz (info);
consteval info
ok1 ()
@@ -28,26 +28,26 @@ ok3 (info i)
}
constexpr info
-bad1 () // { dg-error "function of consteval-only type must be declared .consteval." }
+bad1 ()
{
- return ^^int; // { dg-error "consteval-only expressions" }
+ return ^^int; // { dg-error "consteval-only value" }
}
info
-bad2 () // { dg-error "function of consteval-only type must be declared .consteval." }
+bad2 ()
{
- return ^^int; // { dg-error "consteval-only expressions" }
+ return ^^int; // { dg-error "consteval-only value" }
}
constexpr auto
-bad3 (info i) // { dg-error "function of consteval-only type must be declared .consteval." }
+bad3 (info i)
{
- return i; // { dg-error "consteval-only expressions" }
+ return i;
}
template<info R>
info
-bad4 () // { dg-error "function of consteval-only type must be declared .consteval." }
+bad4 ()
{
- return R; // { dg-error "consteval-only expressions" }
+ return R;
}
new file mode 100644
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+info g = info ();
+
+struct S { info a, b; };
+constexpr S s = { ^^::S };
+static_assert (s.b == info ());
+
+constexpr S s2[2] = { { ^^::S, ^^::S } };
+static_assert (s2[1].a == info ());
+
+S gs = {};
+info garr[3] = { };
+
+constexpr info arr[3] = { ^^::S };
+static_assert (arr[1] == arr[2]);
+static_assert (arr[2] == info ());
+
+struct T { info r; T () = default; };
+constexpr T t {};
+static_assert (t.r == info ());
+
+bool h (S s) { return s.b == info (); }
+
+constexpr info r = info ();
+static_assert (r == info ());
+
+info *k () { static info lg = info (); return ≶ }
@@ -9,12 +9,12 @@ struct B {
};
struct D1 : B {
- consteval virtual void foo() override { } // { dg-error "overriding" }
+ consteval virtual void foo() override { } // { dg-error "overriding non-.consteval. function" }
};
struct D2 : B {
info i;
- consteval virtual void foo() override { }
+ consteval virtual void foo() override { } // { dg-error "overriding non-.consteval. function" }
};
struct D3 : B {
@@ -30,10 +30,10 @@ struct D4 : B2 {
};
struct D5 : B2 {
- virtual void foo() override { } // { dg-error "overriding" }
+ virtual void foo() override { } // { dg-error "overriding .consteval. function" }
};
struct D6 : B2 {
info i;
- virtual void foo() override { } // { dg-error "consteval-only type|overriding" }
+ virtual void foo() override { } // { dg-error "overriding .consteval. function" }
};
@@ -11,6 +11,6 @@ consteval const Base& fn(const Derived& derived) { return derived; }
constexpr Derived obj{.r=^^::}; // OK
constexpr const Derived& d = obj; // OK
-constexpr const Base& b1 = fn(obj); // { dg-error "reference into an object of consteval-only" }
-constexpr const Base& b2 = obj; // { dg-error "reference into an object of consteval-only" }
+constexpr const Base& b1 = fn(obj);
+constexpr const Base& b2 = obj;
constexpr Base b3 = obj;
@@ -5,23 +5,23 @@
using info = decltype(^^int);
consteval void foo (info) { }
-constexpr void bar (info) { } // { dg-error "function of consteval-only type must be declared .consteval." }
-void baz (info) { } // { dg-error "function of consteval-only type must be declared .consteval." }
+constexpr void bar (info) { }
+void baz (info) { }
void
f ()
{
foo (^^void);
- bar (^^void); // { dg-error "consteval-only expressions" }
- baz (^^void); // { dg-error "consteval-only expressions" }
+ bar (^^void); // { dg-error "consteval-only value" }
+ baz (^^void); // { dg-error "consteval-only value" }
}
constexpr void
g ()
{
foo (^^void);
- bar (^^void); // { dg-error "consteval-only expressions" }
- baz (^^void); // { dg-error "consteval-only expressions" }
+ bar (^^void); // { dg-error "consteval-only value" }
+ baz (^^void); // { dg-error "consteval-only value" }
}
consteval void
@@ -5,28 +5,28 @@
using info = decltype(^^int);
struct S {
- int mfn0 (info) { return 0; } // { dg-error "function of consteval-only type must be declared .consteval." }
- constexpr int mfn1 (info) { return 1; } // { dg-error "function of consteval-only type must be declared .consteval." }
+ int mfn0 (info) { return 0; }
+ constexpr int mfn1 (info) { return 1; }
consteval int mfn2 (info) { return 2; }
- int mfn3 (int, info) { return 0; } // { dg-error "function of consteval-only type must be declared .consteval." }
- info mfn4 () { return ^^int; } // { dg-error "consteval-only expressions|function of consteval-only type must be declared .consteval." }
+ int mfn3 (int, info) { return 0; }
+ info mfn4 () { return ^^int; } // { dg-error "consteval-only value" }
};
void
g (S s)
{
- int i0 = s.mfn0 (^^int); // { dg-error "consteval-only expressions" "" { target { ! implicit_constexpr } } }
+ int i0 = s.mfn0 (^^int); // { dg-error "consteval-only value" }
constexpr int i1 = s.mfn1 (^^int);
constexpr int i2 = s.mfn2 (^^int);
- int i3 = s.mfn3 (42, ^^int); // { dg-error "consteval-only expressions" "" { target { ! implicit_constexpr } } }
- info i4 = s.mfn4 (); // { dg-error "consteval-only variable" }
+ int i3 = s.mfn3 (42, ^^int); // { dg-error "consteval-only value" }
+ info i4 = s.mfn4 ();
}
template<typename T>
-int fn (T) { return 4; } // { dg-error "function of consteval-only type must be declared .consteval." }
-const int a = fn (^^int); // { dg-error "consteval-only expressions" }
-int b = fn (^^int); // { dg-error "consteval-only expressions" }
+int fn (T) { return 4; }
+const int a = fn (^^int); // { dg-error "consteval-only value" }
+int b = fn (^^int); // { dg-error "consteval-only value" }
template<typename T>
T fn2 () { return ^^void; } // { dg-error "consteval-only" }
-const info i = fn2<info>(); // { dg-error "consteval-only variable" }
+const info i = fn2<info>();
@@ -10,28 +10,28 @@ void
bar ()
{
constexpr auto [a, b] = A {};
- foo (a); // { dg-error "consteval-only expressions are only allowed in a constant-evaluated context" }
+ foo (a);
}
void
baz ()
{
constexpr auto a = A {};
- foo (a.a); // { dg-error "consteval-only expressions are only allowed in a constant-evaluated context" }
+ foo (a.a);
}
void
qux ()
{
constexpr auto a = A {};
- corge (&a.a); // { dg-error "consteval-only expressions are only allowed in a constant-evaluated context" }
+ corge (&a.a);
}
void
garply ()
{
constexpr auto [a, b] = A {};
- corge (&a); // { dg-error "consteval-only expressions are only allowed in a constant-evaluated context" }
+ corge (&a);
}
void
@@ -17,7 +17,7 @@ struct CE { decltype(^^::) i; };
struct A {
static const Array<CE, 10> mData;
};
-const Array<CE, 10> A::mData{}; // { dg-error "outside a constant-evaluated context" }
+const Array<CE, 10> A::mData{};
struct B {
static constexpr Array<CE, 11> mData{};
@@ -7,13 +7,13 @@ struct A;
void
f1 ()
{
- const auto r = ^^double; // { dg-error "consteval-only variable" }
+ const auto r = ^^double; // { dg-error "consteval-only value" }
constexpr auto r2 = ^^int;
- r2; // { dg-error "consteval-only expressions" }
- ^^void; // { dg-error "consteval-only expressions" }
- ^^int == ^^int; // { dg-error "consteval-only expressions" }
- (void) ^^float; // { dg-error "consteval-only expressions" }
- auto rr = r; // { dg-error "consteval-only variable" }
+ r2; // { dg-error "consteval-only value" }
+ ^^void; // { dg-error "consteval-only value" }
+ ^^int == ^^int; // { dg-error "consteval-only value" }
+ (void) ^^float; // { dg-error "consteval-only value" }
+ auto rr = r2; // { dg-error "consteval-only value" }
constexpr auto x = &(^^int); // { dg-error "lvalue required" }
@@ -28,7 +28,7 @@ f1 ()
constexpr void
f2 ()
{
- auto r = ^^int; // { dg-error "consteval-only variable" }
+ auto r = ^^int; // { dg-error "consteval-only value" }
}
void
new file mode 100644
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], type properties.
+
+#include <meta>
+using namespace std::meta;
+
+using U = std::meta::info;
+using A = U[5];
+struct S { std::meta::info i; };
+
+static_assert (!has_unique_object_representations (^^std::meta::info));
+static_assert (!has_unique_object_representations (^^U));
+static_assert (!has_unique_object_representations (^^S));
+static_assert (!has_unique_object_representations (^^A));
new file mode 100644
@@ -0,0 +1,7 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <typeinfo>
+
+const std::type_info &ti = typeid(decltype(^^int));
+int main () {}
new file mode 100644
@@ -0,0 +1,543 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -g" }
+
+using info = decltype(^^::);
+using size_t = decltype (sizeof 0);
+void *operator new (size_t, void *);
+
+consteval int imm_fn() { return 42; }
+constexpr int not_imm_fn() { return 42; }
+int fn();
+auto id (info i) { return i; }
+
+struct S { info r; };
+struct DS : S { int i; };
+constexpr DS cds{ { ^^int }, 0 };
+DS dsn{ { info{} }, 0 };
+DS ds{ { ^^int }, 0 }; // { dg-error "initialized with a consteval-only value" }
+auto basep1 = (S *) &cds; // { dg-error "initialized with a consteval-only value" }
+constexpr auto basep2 = (S *) &cds;
+
+struct O { consteval int f() const { return 1; } };
+auto pm1 = &O::f; // { dg-error "address of an immediate function" }
+constexpr auto pm2 = &O::f; // { dg-bogus "returns address" "" { xfail *-*-* } }
+
+struct C {
+ info r;
+ constexpr C(info x) : r(x) {}
+};
+constexpr C c1(^^int);
+C c2(info{});
+C c3(^^int); // { dg-error "initialized with a consteval-only value" }
+
+struct CB : C {
+ constexpr CB(info x) : C(x) {}
+};
+constexpr CB cb1(^^int);
+CB cb2(info{});
+CB cb3(^^int); // { dg-error "initialized with a consteval-only value" }
+
+struct Deleg {
+ info r;
+ constexpr Deleg() : Deleg(info{}) {}
+ constexpr Deleg(info x) : r(x) {}
+};
+constexpr Deleg cdlg{};
+Deleg dlg{};
+
+struct N {
+ info i = ^^int;
+};
+
+struct N2 {
+ info i = ^^int; // { dg-error "consteval-only value" }
+ constexpr N2() {} // not immediate-escalating
+ constexpr N2(info x) : i(x) {}
+};
+constexpr N2 cn2a; // { dg-error "constant expression" }
+
+struct N3 {
+ info i = ^^int;
+ consteval N3() {}
+ constexpr N3(info x) : i(x) {}
+};
+constexpr N3 cn3a;
+
+struct N4 {
+ info i = ^^int;
+ constexpr N4() = default;
+ constexpr N4(info x) : i(x) {}
+};
+constexpr N4 cn4a;
+N4 n4a; // { dg-error "initialized with a consteval-only value" }
+
+struct N5 {
+ static constexpr info si = ^^int;
+ static info si2;
+};
+info N5::si2 = ^^int; // { dg-error "initialized with a consteval-only value" }
+
+struct L {
+ static constexpr info si = info{};
+ static info si2;
+};
+info L::si2 = info{};
+
+template<typename T, typename U>
+struct V {
+ T t;
+ U u;
+};
+auto v1 = V{info{}, 42};
+constexpr auto v2 = V{^^int, 42};
+auto v3 = V{^^int, 42}; // { dg-error "initialized with a consteval-only value" }
+
+struct Wrapper { const info &r; };
+Wrapper w1{ ^^int }; // { dg-error "initialized with a consteval-only value" }
+constexpr Wrapper w2{ ^^int };
+
+info a;
+info *pa;
+info **ppa;
+S b;
+S b2{};
+
+template<typename> struct E;
+void foo (E<int> *);
+
+auto normal() -> void {
+ info c;
+ S d;
+}
+
+constexpr auto r = ^^int;
+auto e1 = ^^int; // { dg-error "initialized with a consteval-only value" }
+auto en = info{};
+
+const info &ref1 = r; // { dg-error "initialized with a consteval-only value" }
+constexpr const info &ref2 = r;
+
+constexpr info arr[] = { ^^int, ^^char };
+constexpr info e5 = arr[0];
+info e6 = arr[0]; // { dg-error "initialized with a consteval-only value" }
+auto epast1 = arr + 2; // { dg-error "initialized with a consteval-only value" }
+constexpr auto epast2 = arr + 2;
+info narr[] = { info{}, info{} };
+info narr2[3];
+info narr3[3]{};
+
+// See PR124249. This is OK because the initializer is constant:
+// namespace scope, (r, 42) is a constant expression -> i2 has constant
+// initialization -> the initializer is manifestly constant-evaluated
+// -> r is in an immediate function context -> we accept.
+int i1 = (^^int, 42);
+int i2 = (r, 42);
+int i3 = (info{}, 42);
+// No constant initialization, so not MCE.
+int i4 = (r, fn()); // { dg-error "initialized with a consteval-only value" }
+
+const int &gref = (r, 42);
+
+constexpr N cng{};
+N ng; // { dg-error "initialized with a consteval-only value" }
+static N nsg; // { dg-error "initialized with a consteval-only value" }
+
+constexpr const info *p = &r;
+const info *q = &r; // { dg-error "initialized with a consteval-only value" }
+
+struct Ptr {
+ const info *p;
+};
+auto ptr1 = Ptr{ .p = nullptr };
+constexpr auto ptr2 = Ptr{ .p = &r };
+auto ptr3 = Ptr{ .p = &r }; // { dg-error "initialized with a consteval-only value" }
+
+struct Pair { info r; int i; };
+constexpr Pair p1 = { ^^int, 0 };
+Pair p2 = { info{}, 0 };
+Pair p3 = { ^^int, 0 }; // { dg-error "initialized with a consteval-only value" }
+auto [sb1, sb2] = Pair{^^int, 0}; // { dg-error "initialized with a consteval-only value" }
+constexpr auto [sb3, sb4] = Pair{^^int, 0};
+auto [sb5, sb6] = Pair{info{}, 0};
+
+struct Nested { Pair inner; int c; };
+auto ne = Nested{{^^int, 0}, 1}; // { dg-error "initialized with a consteval-only value" }
+constexpr auto cne = Nested{{^^int, 0}, 1};
+auto ne2 = Nested{{info{}, 0}, 1};
+constexpr auto cne2 = Nested{{info{}, 0}, 1};
+
+consteval auto getr () { return ^^int; }
+consteval auto getnr () { return info{}; }
+constexpr auto r1 = getr ();
+auto r2 = getnr ();
+// r3 is an object with a constituent consteval-only value
+// but is not associated with a constexpr variable.
+auto r3 = getr (); // { dg-error "initialized with a consteval-only value" }
+
+union U { info r; int i; };
+// Only the active member counts here.
+constexpr U u1 = { .i = 0 };
+constexpr U u2 = { .r = ^^int };
+auto u3 = U{ .i = 0 };
+auto u4 = U{ .r = ^^int }; // { dg-error "initialized with a consteval-only value" }
+auto u5 = U{ .r = info{} };
+
+template<bool B>
+void
+tfn ()
+{
+ info rn = B ? info{} : ^^int; // { dg-error "initialized with a consteval-only value" }
+ info ri = B ? ^^int : info{}; // { dg-error "initialized with a consteval-only value" }
+}
+
+template<bool B>
+constexpr void
+ctfn ()
+{
+ info rn = B ? info{} : ^^int;
+ info ri = B ? ^^int : info{};
+}
+
+template<bool B>
+void
+uninst ()
+{
+ info rn = B ? info{} : ^^int;
+ info ri = B ? ^^int : info{};
+}
+
+template<typename>
+constexpr void
+esc ()
+{
+ N n;
+}
+
+void
+dflt (info x = ^^int) // { dg-error "consteval-only value outside an immediate function context" }
+{
+}
+
+void
+dflt_null (info x = info{})
+{
+}
+
+consteval void
+dflt_ok (info x = ^^int)
+{
+}
+
+template<auto V> struct TC { };
+auto e7 = TC<^^int>();
+auto e7n = TC<info{}>();
+
+template<Pair> struct D { };
+auto e8 = D<Pair{^^int, 42}>();
+auto e8n = D<Pair{info{}, 42}>();
+
+void
+g (bool b)
+{
+ info null;
+ null = info();
+
+ constexpr auto lr = ^^int;
+ auto e2 = ^^int; // { dg-error "initialized with a consteval-only value" }
+ auto en = info{};
+ static constexpr info sg = ^^int;
+ static info sg2 = ^^int; // { dg-error "initialized with a consteval-only value" }
+ const info &lref1 = r; // { dg-error "initialized with a consteval-only value" }
+ constexpr const info &lref2 = r;
+
+ // Don't accept these: the "has constant initialization" rule applies to
+ // variables at namespace scope only.
+ int e3 = (^^int, 42); // { dg-error "initialized with a consteval-only value" }
+ int e4 = (r, 42); // { dg-error "initialized with a consteval-only value" }
+ int e5 = (r, fn()); // { dg-error "initialized with a consteval-only value" }
+ // But these are static.
+ static int e6 = (^^int, 42);
+ static int e7 = (r, 42);
+ static int e8 = (r, fn()); // { dg-error "initialized with a consteval-only value" }
+
+ // grok_reference_init turns the init into
+ // (const int &) &D.2686 and so store_init_value won't see
+ // any consteval-only value.
+ const int &ref = (r, 42); // { dg-error "initialized with a consteval-only value" "" { xfail *-*-* } }
+
+ info rn = b ? info{} : ^^int; // { dg-error "initialized with a consteval-only value" }
+ info ri = b ? ^^int : info{}; // { dg-error "initialized with a consteval-only value" }
+
+ constexpr info larr[] = { ^^int, ^^char };
+ constexpr info le5 = arr[0];
+ info le6 = arr[0]; // { dg-error "initialized with a consteval-only value" }
+ info lnarr[] = { info{}, info{} };
+
+ constexpr const info *lp = &r;
+ const info *lq = &r; // { dg-error "initialized with a consteval-only value" }
+
+ constexpr C lc1(^^int);
+ C lc2(info{});
+ C lc3(^^int); // { dg-error "initialized with a consteval-only value" }
+
+ constexpr CB lcb1(^^int);
+ CB lcb2(info{});
+ CB lcb3(^^int); // { dg-error "initialized with a consteval-only value" }
+
+ Wrapper lw1{ ^^int }; // { dg-error "initialized with a consteval-only value" }
+ // w2 at block scope has this initializer:
+ // {.r=(<<< Unknown tree: lang_type >>> &) &_ZGRL2w2_}
+ // which is reduced_constant_expression_p but here we have
+ // {.r=(<<< Unknown tree: lang_type >>> &) &D.2718}
+ // which is not reduced_constant_expression_p. The error
+ // also happens without reflection:
+ // struct W { const int &r; }
+ // void h () { constexpr W lw{42}; }
+ constexpr Wrapper lw2{ ^^int }; // { dg-error "not a constant expression" }
+
+ constexpr N lcng{};
+ N lng; // { dg-error "initialized with a consteval-only value" }
+
+ constexpr Pair p4 = { ^^int, 0 };
+ Pair p5 = { info{}, 0 };
+ Pair p6 = { ^^int, 0 }; // { dg-error "initialized with a consteval-only value" }
+ auto [lsb1, lsb2] = Pair{^^int, 0}; // { dg-error "initialized with a consteval-only value" }
+ constexpr auto [lsb3, lsb4] = Pair{^^int, 0};
+ auto [lsb5, lsb6] = Pair{info{}, 0};
+
+ auto lptr1 = Ptr{ .p = nullptr };
+ constexpr auto lptr2 = Ptr{ .p = &r };
+ auto lptr3 = Ptr{ .p = &r }; // { dg-error "initialized with a consteval-only value" }
+
+ auto lne = Nested{{^^int, 0}, 1}; // { dg-error "initialized with a consteval-only value" }
+ constexpr auto lcne = Nested{{^^int, 0}, 1};
+ auto lne2 = Nested{{info{}, 0}, 1};
+ constexpr auto lcne2 = Nested{{info{}, 0}, 1};
+
+ constexpr DS lcds{ { ^^int }, 0 };
+ DS ldsn{ { info{} }, 0 };
+ DS lds{ { ^^int }, 0 }; // { dg-error "initialized with a consteval-only value" }
+ auto lbasep1 = (S *) &cds; // { dg-error "initialized with a consteval-only value" }
+ constexpr auto lbasep2 = (S *) &cds;
+
+ constexpr U lu1 = { .i = 0 };
+ constexpr U lu2 = { .r = ^^int };
+ auto lu3 = U{ .i = 0 };
+ auto lu4 = U{ .r = ^^int }; // { dg-error "initialized with a consteval-only value" }
+ auto lu5 = U{ .r = info{} };
+
+ constexpr auto lr1 = getr ();
+ auto lr2 = getnr ();
+ auto lr3 = getr (); // { dg-error "initialized with a consteval-only value" }
+
+ // We think that [expr.const.imm]/2 gives us the rationale for
+ // rejecting this code, even though r isn't ODR-used here.
+ ^^int; // { dg-error "consteval-only value outside an immediate function context" }
+ r; // { dg-error "consteval-only value outside an immediate function context" }
+ (^^int, true); // { dg-error "consteval-only value outside an immediate function context" }
+ (r, true); // { dg-error "consteval-only value outside an immediate function context" }
+ lr; // { dg-error "consteval-only value outside an immediate function context" }
+
+ a = info();
+ a = ^^int; // { dg-error "consteval-only value outside an immediate function context" }
+ a = r; // { dg-error "consteval-only value outside an immediate function context" }
+
+ a == a;
+ a == ^^int; // { dg-error "consteval-only value outside an immediate function context" }
+ ^^int != info{}; // { dg-error "consteval-only value outside an immediate function context" }
+ ^^int == ^^int; // { dg-error "consteval-only value outside an immediate function context" }
+ constexpr bool b1 = ^^int != info{};
+ constexpr bool b2 = ^^int == ^^int;
+
+ a == r; // { dg-error "consteval-only value outside an immediate function context" }
+
+ constexpr N cln;
+ N ln; // { dg-error "initialized with a consteval-only value" }
+
+ new (&a) info();
+ new (&a) info(^^int); // { dg-error "consteval-only value outside an immediate function context" }
+ new info(info{});
+ new info(^^int); // { dg-error "consteval-only value outside an immediate function context" }
+
+ S{};
+ S{.r={}};
+ S{.r=^^int}; // { dg-error "consteval-only value outside an immediate function context" }
+
+ auto lam = [] { info l = ^^int; };
+ lam ();
+
+ auto lam2 = [] { return ^^int; };
+ auto e9 = lam2 (); // { dg-error "initialized with a consteval-only value" }
+ constexpr auto e10 = lam2 ();
+ constexpr auto lam3 = [i = ^^int]{ return i; };
+ auto lam4 = [i = ^^int]{ return i; }; // { dg-error "initialized with a consteval-only value" }
+ auto lam5 = [lr]{ return lr; }; // { dg-error "initialized with a consteval-only value" }
+ constexpr auto lam6 = [lr]{ return lr; };
+
+ if consteval {
+ auto ifc = ^^int;
+ }
+
+ auto x1 = imm_fn ();
+ auto x2 = []() consteval { return ^^int; }(); // { dg-error "initialized with a consteval-only value" }
+
+ id (null);
+ id (^^int); // { dg-error "consteval-only value outside an immediate function context" }
+ dflt ();
+ dflt_null ();
+ dflt_ok ();
+ tfn<true>();
+ ctfn<true>();
+ esc<int>();
+}
+
+consteval void
+ceg (bool b)
+{
+ info null;
+ null = info();
+
+ constexpr auto lr = ^^int;
+ auto e2 = ^^int;
+ static constexpr info sg = ^^int;
+ static info sg2 = ^^int;
+ const info &lref1 = r;
+ constexpr const info &lref2 = r;
+
+ int e3 = (^^int, 42);
+ int e4 = (r, 42);
+ int e5 = (r, fn());
+ static int e6 = (^^int, 42);
+ static int e7 = (r, 42);
+ static int e8 = (r, fn());
+
+ const int &ref = (r, 42);
+
+ info rn = b ? info{} : ^^int;
+ info ri = b ? ^^int : info{};
+
+ constexpr info larr[] = { ^^int, ^^char };
+ constexpr info le5 = arr[0];
+ info le6 = arr[0];
+ info lnarr[] = { info{}, info{} };
+
+ constexpr const info *lp = &r;
+ const info *lq = &r;
+
+ constexpr C lc1(^^int);
+ C lc2(info{});
+ C lc3(^^int);
+
+ constexpr CB lcb1(^^int);
+ CB lcb2(info{});
+ CB lcb3(^^int);
+
+ Wrapper lw1{ ^^int };
+
+ constexpr N lcng{};
+ N lng;
+
+ constexpr Pair p4 = { ^^int, 0 };
+ Pair p5 = { info{}, 0 };
+ Pair p6 = { ^^int, 0 };
+ auto [lsb1, lsb2] = Pair{^^int, 0};
+ constexpr auto [lsb3, lsb4] = Pair{^^int, 0};
+ auto [lsb5, lsb6] = Pair{info{}, 0};
+
+ auto lptr1 = Ptr{ .p = nullptr };
+ constexpr auto lptr2 = Ptr{ .p = &r };
+ auto lptr3 = Ptr{ .p = &r };
+
+ auto lne = Nested{{^^int, 0}, 1};
+ constexpr auto lcne = Nested{{^^int, 0}, 1};
+ auto lne2 = Nested{{info{}, 0}, 1};
+ constexpr auto lcne2 = Nested{{info{}, 0}, 1};
+
+ constexpr DS lcds{ { ^^int }, 0 };
+ DS ldsn{ { info{} }, 0 };
+ DS lds{ { ^^int }, 0 };
+ auto lbasep1 = (S *) &cds;
+ constexpr auto lbasep2 = (S *) &cds;
+
+ constexpr U lu1 = { .i = 0 };
+ constexpr U lu2 = { .r = ^^int };
+ auto lu3 = U{ .i = 0 };
+ auto lu4 = U{ .r = ^^int };
+ auto lu5 = U{ .r = info{} };
+
+ constexpr auto lr1 = getr ();
+ auto lr2 = getnr ();
+ auto lr3 = getr ();
+
+ ^^int;
+ r;
+ lr;
+ (^^int, true);
+ (r, true);
+
+ a = info();
+ a = ^^int;
+ a = r;
+
+ a == a;
+ a == ^^int;
+ ^^int != info{};
+ ^^int == ^^int;
+ constexpr bool b1 = ^^int != info{};
+ constexpr bool b2 = ^^int == ^^int;
+
+ a == r;
+
+ constexpr N cln;
+ N ln;
+
+ new (&a) info();
+ new (&a) info(^^int);
+ new info(info{});
+ new info(^^int);
+
+ S{};
+ S{.r={}};
+ S{.r=^^int};
+
+ auto lam = [] { info l = ^^int; };
+ lam ();
+
+ auto lam2 = [] { return ^^int; };
+ auto e9 = lam2 ();
+ constexpr auto e10 = lam2 ();
+ constexpr auto lam3 = [i = ^^int]{ return i; };
+ auto lam4 = [i = ^^int]{ return i; };
+ auto lam5 = [lr]{ return lr; };
+ constexpr auto lam6 = [lr]{ return lr; };
+
+ if consteval {
+ auto ifc = ^^int;
+ }
+
+ auto x1 = imm_fn ();
+ auto x2 = []() consteval { return ^^int; }();
+
+ id (null);
+ id (^^int);
+}
+
+constexpr void
+cg (bool b)
+{
+ int e3 = (^^int, 42); // { dg-error "initialized with a consteval-only value" }
+ int e4 = (r, 42); // { dg-error "initialized with a consteval-only value" }
+ int e5 = (r, fn()); // { dg-error "initialized with a consteval-only value" }
+ static int e6 = (^^int, 42);
+ static int e7 = (r, 42);
+ static int e8 = (r, fn()); // { dg-error "initialized with a consteval-only value" }
+
+ info rn = b ? info{} : ^^int; // { dg-error "initialized with a consteval-only value" }
+ info ri = b ? ^^int : info{}; // { dg-error "initialized with a consteval-only value" }
+
+ constexpr auto lr1 = getr ();
+ auto lr2 = getnr ();
+ auto lr3 = getr (); // { dg-error "consteval-only value" }
+}
new file mode 100644
@@ -0,0 +1,32 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+// [expr.const.const]
+
+consteval int plus1(int x) { return x + 1; }
+template <auto V> struct C { };
+
+auto a = plus1; // { dg-error "taking address of an immediate function" }
+constexpr auto b = plus1; // // { dg-bogus "returns address" "" { xfail *-*-* } } OK
+auto c = C<plus1>(); // OK
+
+auto d = ^^int; // { dg-error "initialized with a consteval-only value" }
+auto e = C<^^char>(); // OK
+
+// [expr.const.imm]
+
+consteval info refl() { return ^^int; }
+template <auto F>
+constexpr void ex() {
+ auto x = F();
+}
+auto p = &ex<refl>; // { dg-error "taking address of an immediate function" }
+
+consteval int id(int x) { return x; }
+template <auto F>
+constexpr auto apply_to(int i) { return F(i); }
+auto q = &apply_to<id>; // { dg-error "taking address of an immediate function" }
new file mode 100644
@@ -0,0 +1,63 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -g" }
+
+using info = decltype(^^::);
+
+struct A { info i; };
+struct B : A { };
+struct C { A a; };
+struct D { info i1, i2, i3; };
+struct E { C c; info i; };
+struct F { A a[10]; };
+struct G { info i = info{}; };
+
+A a1 = { info{} };
+A a2{ info{} };
+B b1 = { info{} };
+B b2{ info{} };
+C c1 = { { info{} } };
+C c2{ { info{} } };
+D d1 = { info{}, info{}, info{} };
+D d2{ info{}, info{}, info{} };
+E e1 = { { { info{} } }, info{} };
+E e2{ { { info{} } }, info{} };
+F f1 = { { { info{} }, { info{} } } };
+F f2{ { { info{} }, { info{} } } };
+G g1{};
+G g2;
+
+void
+fn ()
+{
+ A la1 = { info{} };
+ A la2{ info{} };
+ B lb1 = { info{} };
+ B lb2{ info{} };
+ C lc1 = { { info{} } };
+ C lc2{ { info{} } };
+ D ld1 = { info{}, info{}, info{} };
+ D ld2{ info{}, info{}, info{} };
+ E le1 = { { { info{} } }, info{} };
+ E le2{ { { info{} } }, info{} };
+ F lf1 = { { { info{} }, { info{} } } };
+ F lf2{ { { info{} }, { info{} } } };
+ G lg1{};
+ G lg2;
+
+ static A sa1 = { info{} };
+ static A sa2{ info{} };
+ static B sb1 = { info{} };
+ static B sb2{ info{} };
+ static C sc1 = { { info{} } };
+ static C sc2{ { info{} } };
+ static D sd1 = { info{}, info{}, info{} };
+ static D sd2{ info{}, info{}, info{} };
+ static E se1 = { { { info{} } }, info{} };
+ static E se2{ { { info{} } }, info{} };
+ static F sf1 = { { { info{} }, { info{} } } };
+ static F sf2{ { { info{} }, { info{} } } };
+ static G sg1{};
+ static G sg2;
+}
new file mode 100644
@@ -0,0 +1,24 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+struct V { int a, b, c; };
+constexpr info varr[] = { ^^V::a, ^^V::b, ^^V::c };
+constexpr const info *p = varr;
+static_assert (p[0] == ^^V::a);
+static_assert (p[1] == ^^V::b);
+static_assert (p[2] == ^^V::c);
+static_assert (varr[0] == ^^V::a);
+
+constexpr info arr[] = { ^^int, ^^double };
+auto q = &arr[0]; // { dg-error ".q. is initialized with a consteval-only value but is not declared .constexpr." }
+
+void
+fn ()
+{
+ auto r = arr; // { dg-error ".r. is initialized with a consteval-only value but is not declared .constexpr." }
+ (void) r;
+}
new file mode 100644
@@ -0,0 +1,40 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+struct S
+{
+ info i;
+ int n;
+};
+
+constexpr info arr[] = { ^^int, ^^double, ^^char };
+constexpr S s = { ^^int, 42 };
+constexpr S sarr[2] = { { ^^int, 1 }, { ^^double, 2 } };
+constexpr const info *p = arr;
+
+// These check check_out_of_consteval_use which uses a tree walk
+// on its expr. value6.C checks consteval_only_p not used in
+// a tree walk.
+const void *vp = &p; // { dg-error "initialized with a consteval-only value" }
+
+const auto p1 = &arr[0]; // { dg-error "initialized with a consteval-only value" }
+const auto p2 = arr; // { dg-error "initialized with a consteval-only value" }
+const auto p3 = arr + 1; // { dg-error "initialized with a consteval-only value" }
+const auto p4 = arr + 3; // { dg-error "initialized with a consteval-only value" }
+const auto p5 = &s; // { dg-error "initialized with a consteval-only value" }
+const auto p6 = &s.i; // { dg-error "initialized with a consteval-only value" }
+const auto p7 = &sarr[1]; // { dg-error "initialized with a consteval-only value" }
+const auto p8 = &sarr[1].i; // { dg-error "initialized with a consteval-only value" }
+
+struct Holder { const info *p; int n; };
+auto h = Holder{ &arr[0], 1 }; // { dg-error "initialized with a consteval-only value" }
+
+constexpr bool cond = true;
+const auto p_cond = cond ? &arr[0] : &arr[1]; // { dg-error "initialized with a consteval-only value" }
+
+// Not an error.
+auto pdm = &S::i;
new file mode 100644
@@ -0,0 +1,41 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+struct S
+{
+ info i;
+ int n;
+};
+
+constexpr info arr[] = { ^^int, ^^double, ^^char };
+constexpr S s = { ^^int, 42 };
+constexpr S sarr[2] = { { ^^int, 1 }, { ^^double, 2 } };
+constexpr const info *p = arr;
+
+constexpr const void *vp = &p;
+
+// This tests that consteval_only_value_p properly detects
+// consteval-only values when they are in ADDR_EXPR, POINTER_PLUS_EXPR,
+// ARRAY_REF, and similar. A failure would result in a link error.
+constexpr const auto p1 = &arr[0];
+constexpr const auto p2 = arr;
+constexpr const auto p3 = arr + 1;
+constexpr const auto p4 = arr + 3;
+constexpr const auto p5 = &s;
+constexpr const auto p6 = &s.i;
+constexpr const auto p7 = &sarr[1];
+constexpr const auto p8 = &sarr[1].i;
+
+constexpr bool cond = true;
+constexpr auto p_cond = cond ? &arr[0] : &arr[1];
+
+struct Holder { const info *p; int n; };
+constexpr Holder h = { &arr[0], 1 };
+
+constexpr auto cpdm = &S::i;
+
+int main () {}
new file mode 100644
@@ -0,0 +1,52 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Like value6.C, but with function-local static.
+
+using info = decltype(^^::);
+
+struct S
+{
+ info i;
+ int n;
+};
+struct Holder { const info *p; int n; };
+
+void
+g ()
+{
+ constexpr static info arr[] = { ^^int, ^^double, ^^char };
+ constexpr static S s = { ^^int, 42 };
+ constexpr static S sarr[2] = { { ^^int, 1 }, { ^^double, 2 } };
+ constexpr static const info *p = arr;
+
+ constexpr const void *vp = &p;
+ constexpr const auto p1 = &arr[0];
+ constexpr const auto p2 = arr;
+ constexpr const auto p3 = arr + 1;
+ constexpr const auto p4 = arr + 3;
+ constexpr const auto p5 = &s;
+ constexpr const auto p6 = &s.i;
+ constexpr const auto p7 = &sarr[1];
+ constexpr const auto p8 = &sarr[1].i;
+ constexpr bool cond = true;
+ constexpr auto p_cond = cond ? &arr[0] : &arr[1];
+ constexpr Holder h = { &arr[0], 1 };
+ constexpr auto cpdm = &S::i;
+
+ constexpr static const void *svp = &p;
+ constexpr static const auto sp1 = &arr[0];
+ constexpr static const auto sp2 = arr;
+ constexpr static const auto sp3 = arr + 1;
+ constexpr static const auto sp4 = arr + 3;
+ constexpr static const auto sp5 = &s;
+ constexpr static const auto sp6 = &s.i;
+ constexpr static const auto sp7 = &sarr[1];
+ constexpr static const auto sp8 = &sarr[1].i;
+ constexpr static auto sp_cond = cond ? &arr[0] : &arr[1];
+ constexpr static Holder sh = { &arr[0], 1 };
+ constexpr static auto scpdm = &S::i;
+}
+
+int main () {}
new file mode 100644
@@ -0,0 +1,26 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+// No use of Reflection in this test, but it crashed with Reflection
+// enabled.
+
+#include <vector>
+#include <ranges>
+
+using VVI = std::vector<std::vector<int>>;
+using JV = decltype (std::views::join (std::declval<VVI> ()));
+
+static_assert (std::ranges::input_range<JV>);
+static_assert (std::ranges::forward_range<JV>);
+
+int
+main ()
+{
+ VVI vv { { 1, 2 }, { 3, 4, 5 } };
+ int n = 0;
+ for (auto &elt : vv | std::views::join)
+ {
+ (void) elt;
+ ++n;
+ }
+ return n == 5 ? 0 : 1;
+}
@@ -1860,6 +1860,8 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
switch (code)
{
+ /* This could represent the C++ std::meta::info type. */
+ case LANG_TYPE:
case NULLPTR_TYPE:
gcc_assert (hwi == 0);
/* Fallthru. */
@@ -2035,6 +2037,8 @@ cache_integer_cst (tree t, bool might_duplicate ATTRIBUTE_UNUSED)
wide_int_to_type_1. */
switch (TREE_CODE (type))
{
+ /* This could represent the C++ std::meta::info type. */
+ case LANG_TYPE:
case NULLPTR_TYPE:
gcc_checking_assert (integer_zerop (t));
/* Fallthru. */
@@ -113,7 +113,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
consteval exception& operator=(const exception&) = default;
consteval exception& operator=(exception&&) = default;
- consteval const char*
+ constexpr const char*
what() const noexcept override
{
// If u8string is not empty and string is empty, conversion