cpp_define (pfile, "__cpp_pp_embed=202502L");
cpp_define (pfile, "__cpp_constexpr_virtual_inheritance=202506L");
cpp_define (pfile, "__cpp_trivial_relocatability=202502L");
+ cpp_define (pfile, "__cpp_expansion_statements=202506L");
}
if (flag_concepts && cxx_dialect > cxx14)
cpp_define (pfile, "__cpp_concepts=202002L");
/* P2718R0 - in C++23 for-range-initializer, extend all temps. */
if (DECL_NAME (decl) == for_range__identifier
- && flag_range_for_ext_temps)
+ && flag_range_for_ext_temps
+ /* Iterating expansion statement decl is static right now, but that
+ could change depending on CWG3044 and CWG3043. */
+ && !TREE_STATIC (decl))
{
gcc_checking_assert (!cond_guard);
return extend_all_temps (decl, init, cleanups);
case CO_AWAIT_EXPR:
case CO_YIELD_EXPR:
case CO_RETURN_EXPR:
+ case TEMPLATE_FOR_STMT:
if (flags & tf_error)
constexpr_error (cp_expr_loc_or_loc (t, input_location), fundef_p,
"%qE is not a constant expression", t);
MARK_TS_EXP (IF_STMT);
MARK_TS_EXP (OMP_DEPOBJ);
MARK_TS_EXP (RANGE_FOR_STMT);
+ MARK_TS_EXP (TEMPLATE_FOR_STMT);
MARK_TS_EXP (TRY_BLOCK);
MARK_TS_EXP (USING_STMT);
templates. */
DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6)
+/* Used to represent an expansion-statement. The operands are
+ TEMPLATE_FOR_DECL, TEMPLATE_FOR_EXPR, TEMPLATE_FOR_BODY,
+ TEMPLATE_FOR_SCOPE, and TEMPLATE_FOR_INIT_STMT, respectively. */
+DEFTREECODE (TEMPLATE_FOR_STMT, "template_for_stmt", tcc_statement, 5)
+
/* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to
obtain the expression. */
DEFTREECODE (EXPR_STMT, "expr_stmt", tcc_expression, 1)
of consteval if statement. Also set while processing an immediate
invocation. */
BOOL_BITFIELD consteval_if_p : 1;
+ /* Nonzero if we are parsing the substatement of expansion-statement. */
+ BOOL_BITFIELD expansion_stmt : 1;
int unevaluated_operand;
int inhibit_evaluation_warnings;
#define in_discarded_stmt scope_chain->discarded_stmt
#define in_consteval_if_p scope_chain->consteval_if_p
+#define in_expansion_stmt scope_chain->expansion_stmt
#define current_ref_temp_count scope_chain->ref_temp_count
#define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE))
#define RANGE_FOR_NOVECTOR(NODE) TREE_LANG_FLAG_5 (RANGE_FOR_STMT_CHECK (NODE))
+/* TEMPLATE_FOR_STMT accessors. These give access to the declarator,
+ expression, body, and scope of the statement, respectively. */
+#define TEMPLATE_FOR_DECL(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 0)
+#define TEMPLATE_FOR_EXPR(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 1)
+#define TEMPLATE_FOR_BODY(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 2)
+#define TEMPLATE_FOR_SCOPE(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 3)
+#define TEMPLATE_FOR_INIT_STMT(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 4)
+
/* STMT_EXPR accessor. */
#define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0)
/* The original node. TLDCL can be a DECL (for a function or static
data member), a TYPE (for a class), depending on what we were
- asked to instantiate, or a TREE_LIST with the template as PURPOSE
- and the template args as VALUE, if we are substituting for
- overload resolution. In all these cases, TARGS is NULL.
+ asked to instantiate, a TEMPLATE_FOR_STMT (for instantiation
+ of expansion stmt body outside of templates) or a TREE_LIST with
+ the template as PURPOSE and the template args as VALUE, if we are
+ substituting for overload resolution. In all these cases, TARGS
+ is NULL.
However, to avoid creating TREE_LIST objects for substitutions if
we can help, we store PURPOSE and VALUE in TLDCL and TARGS,
respectively. So TLDCL stands for TREE_LIST or DECL (the
struct cp_decomp { tree decl; unsigned int count; };
extern void cp_finish_decl (tree, tree, bool, tree, int, cp_decomp * = nullptr);
extern tree lookup_decomp_type (tree);
+HOST_WIDE_INT cp_decomp_size (location_t, tree, tsubst_flags_t);
extern bool cp_finish_decomp (tree, cp_decomp *, bool = false);
extern int cp_complete_array_type (tree *, tree, bool);
extern int cp_complete_array_type_or_error (tree *, tree, bool, tsubst_flags_t);
extern bool maybe_clone_body (tree);
/* In parser.cc */
+extern tree cp_build_range_for_decls (location_t, tree, tree *, bool);
extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool,
tree, bool);
+extern tree build_range_temp (tree);
+extern tree cp_perform_range_for_lookup (tree, tree *, tree *,
+ tsubst_flags_t = tf_warning_or_error);
extern void cp_convert_omp_range_for (tree &, tree &, tree &,
tree &, tree &, tree &, tree &, tree &,
bool);
extern tree add_outermost_template_args (tree, tree);
extern tree add_extra_args (tree, tree, tsubst_flags_t, tree);
extern tree build_extra_args (tree, tree, tsubst_flags_t);
+extern void finish_expansion_stmt (tree, tree, tsubst_flags_t, tree);
/* in rtti.cc */
/* A vector of all tinfo decls that haven't been emitted yet. */
extern int stmts_are_full_exprs_p (void);
extern void init_cp_semantics (void);
extern tree do_poplevel (tree);
+extern tree do_pushlevel (scope_kind);
extern void break_maybe_infinite_loop (void);
extern void add_decl_expr (tree);
extern tree maybe_cleanup_point_expr_void (tree);
extern void finish_for_stmt (tree);
extern tree begin_range_for_stmt (tree, tree);
extern void finish_range_for_decl (tree, tree, tree);
-extern void finish_range_for_stmt (tree);
+extern tree begin_template_for_scope (tree *);
extern tree finish_break_stmt (void);
extern tree finish_continue_stmt (void);
extern tree begin_switch_stmt (void);
pp_needs_newline (this) = true;
break;
+ case TEMPLATE_FOR_STMT:
+ pp_cxx_ws_string (this, "template for");
+ pp_space (this);
+ pp_cxx_left_paren (this);
+ if (TEMPLATE_FOR_INIT_STMT (t))
+ {
+ statement (TEMPLATE_FOR_INIT_STMT (t));
+ pp_needs_newline (this) = false;
+ pp_cxx_whitespace (this);
+ }
+ statement (TEMPLATE_FOR_DECL (t));
+ pp_space (this);
+ pp_needs_newline (this) = false;
+ pp_colon (this);
+ pp_space (this);
+ statement (TEMPLATE_FOR_EXPR (t));
+ pp_cxx_right_paren (this);
+ pp_newline_and_indent (this, 3);
+ statement (TEMPLATE_FOR_BODY (t));
+ pp_indentation (this) -= 3;
+ pp_needs_newline (this) = true;
+ break;
+
/* expression-statement:
expression(opt) ; */
case EXPR_STMT:
ent->in_stmt_expr = true;
break;
case sk_block:
- if (level_for_constexpr_if (bl->level_chain))
+ if (level_for_constexpr_if (obl))
ent->in_constexpr_if = true;
- else if (level_for_consteval_if (bl->level_chain))
+ else if (level_for_consteval_if (obl))
ent->in_consteval_if = true;
break;
default:
tree label;
/* For templates, just add the case label; we'll do semantic
- analysis at instantiation-time. */
+ analysis at instantiation-time. But diagnose case labels
+ in expansion statements with switch outside of it here. */
+ if (in_expansion_stmt)
+ for (cp_binding_level *b = current_binding_level;
+ b != switch_stack->level; b = b->level_chain)
+ if (b->kind == sk_template_for && b->this_entity)
+ {
+ auto_diagnostic_group d;
+ error ("jump to case label");
+ inform (EXPR_LOCATION (b->this_entity),
+ " enters %<template for%> statement");
+ return error_mark_node;
+ }
label = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node);
return add_stmt (build_case_label (low_value, high_value, label));
}
error has been diagnosed. */
static tree
-find_decomp_class_base (location_t loc, tree type, tree ret)
+find_decomp_class_base (location_t loc, tree type, tree ret,
+ tsubst_flags_t complain)
{
if (LAMBDA_TYPE_P (type))
{
- auto_diagnostic_group d;
- error_at (loc, "cannot decompose lambda closure type %qT", type);
- inform (location_of (type), "lambda declared here");
+ if (complain & tf_error)
+ {
+ auto_diagnostic_group d;
+ error_at (loc, "cannot decompose lambda closure type %qT", type);
+ inform (location_of (type), "lambda declared here");
+ }
return error_mark_node;
}
return type;
else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
+ if ((complain & tf_error) == 0)
+ return error_mark_node;
auto_diagnostic_group d;
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
error_at (loc, "cannot decompose class type %qT because it has an "
}
else if (!accessible_p (type, field, true))
{
+ if ((complain & tf_error) == 0)
+ return error_mark_node;
auto_diagnostic_group d;
error_at (loc, "cannot decompose inaccessible member %qD of %qT",
field, type);
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
auto_diagnostic_group d;
- tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret);
+ tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret,
+ complain);
if (t == error_mark_node)
{
- inform (location_of (type), "in base class of %qT", type);
+ if (complain & tf_error)
+ inform (location_of (type), "in base class of %qT", type);
return error_mark_node;
}
if (t != NULL_TREE && t != ret)
{
if (ret == type)
{
- error_at (loc, "cannot decompose class type %qT: both it and "
- "its base class %qT have non-static data members",
- type, t);
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose class type %qT: both it and "
+ "its base class %qT have non-static data "
+ "members", type, t);
return error_mark_node;
}
else if (orig_ret != NULL_TREE)
return t;
else if (ret != NULL_TREE)
{
- error_at (loc, "cannot decompose class type %qT: its base "
- "classes %qT and %qT have non-static data "
- "members", type, ret, t);
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose class type %qT: its base "
+ "classes %qT and %qT have non-static data "
+ "members", type, ret, t);
return error_mark_node;
}
else
}
}
+/* Return structured binding size of TYPE or -1 if erroneous. */
+
+HOST_WIDE_INT
+cp_decomp_size (location_t loc, tree type, tsubst_flags_t complain)
+{
+ if (TYPE_REF_P (type))
+ {
+ type = complete_type (TREE_TYPE (type));
+ if (type == error_mark_node)
+ return -1;
+ if (!COMPLETE_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ error_at (loc, "structured binding refers to incomplete type %qT",
+ type);
+ return -1;
+ }
+ }
+
+ unsigned HOST_WIDE_INT eltscnt = 0;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (TYPE_DOMAIN (type) == NULL_TREE)
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose array of unknown bound %qT",
+ type);
+ return -1;
+ }
+ tree nelts = array_type_nelts_top (type);
+ if (nelts == error_mark_node)
+ return -1;
+ if (!tree_fits_shwi_p (nelts))
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose variable length array %qT", type);
+ return -1;
+ }
+ return tree_to_shwi (nelts);
+ }
+ /* 2 GNU extensions. */
+ else if (TREE_CODE (type) == COMPLEX_TYPE)
+ return 2;
+ else if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&eltscnt))
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose variable length vector %qT", type);
+ return -1;
+ }
+ return eltscnt;
+ }
+ else if (tree tsize = get_tuple_size (type))
+ {
+ if (tsize == error_mark_node
+ || !tree_fits_shwi_p (tsize)
+ || tree_int_cst_sgn (tsize) < 0)
+ {
+ if (complain & tf_error)
+ error_at (loc, "%<std::tuple_size<%T>::value%> is not an integral "
+ "constant expression", type);
+ return -1;
+ }
+ return tree_to_shwi (tsize);
+ }
+ else if (TREE_CODE (type) == UNION_TYPE)
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose union type %qT", type);
+ return -1;
+ }
+ else if (!CLASS_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose non-array non-class type %qT", type);
+ return -1;
+ }
+ else if (processing_template_decl && complete_type (type) == error_mark_node)
+ return -1;
+ else if (processing_template_decl && !COMPLETE_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ pedwarn (loc, 0, "structured binding refers to incomplete class type "
+ "%qT", type);
+ return -1;
+ }
+ else
+ {
+ tree btype = find_decomp_class_base (loc, type, NULL_TREE, complain);
+ if (btype == error_mark_node)
+ return -1;
+ else if (btype == NULL_TREE)
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose class type %qT without non-static "
+ "data members", type);
+ return -1;
+ }
+ for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) != FIELD_DECL
+ || DECL_ARTIFICIAL (field)
+ || DECL_UNNAMED_BIT_FIELD (field))
+ continue;
+ else
+ eltscnt++;
+ return eltscnt;
+ }
+}
+
/* Finish a decomposition declaration. DECL is the underlying declaration
"e", FIRST is the head of a chain of decls for the individual identifiers
chained through DECL_CHAIN in reverse order and COUNT is the number of
type);
else
{
- tree btype = find_decomp_class_base (loc, type, NULL_TREE);
+ tree btype = find_decomp_class_base (loc, type, NULL_TREE,
+ tf_warning_or_error);
if (btype == error_mark_node)
goto error_out;
else if (btype == NULL_TREE)
bool
decl_dependent_p (tree decl)
{
+ tree orig_decl = decl;
if (DECL_FUNCTION_SCOPE_P (decl)
|| TREE_CODE (decl) == CONST_DECL
|| TREE_CODE (decl) == USING_DECL
if (LAMBDA_FUNCTION_P (decl)
&& dependent_type_p (DECL_CONTEXT (decl)))
return true;
+ /* for-range-declaration of expansion statement as well as variable
+ declarations in the expansion statement body when the expansion statement
+ is not inside a template still need to be treated as dependent during
+ parsing. When the body is instantiated, in_expansion_stmt will be already
+ false. */
+ if (VAR_P (orig_decl) && in_expansion_stmt && decl == current_function_decl)
+ return true;
return false;
}
= ((!text_output.show_nesting_p ())
|| text_output.show_locations_in_nesting_p ());
char *indent = text_output.build_indent_prefix (true);
+ bool expansion_stmt_p = TREE_CODE (p->tldcl) == TEMPLATE_FOR_STMT;
pp_verbatim (text_output.get_printer (),
- p->list_p ()
+ expansion_stmt_p
+ ? G_("%s%s%sIn instantiation of %<template for%> "
+ "iteration %E:\n")
+ : p->list_p ()
? G_("%s%s%sIn substitution of %qS:\n")
: G_("%s%s%sIn instantiation of %q#D:\n"),
indent,
show_file ? LOCATION_FILE (location) : "",
show_file ? ": " : "",
- p->get_node ());
+ expansion_stmt_p
+ ? TREE_VEC_ELT (p->targs, 0)
+ : p->get_node ());
free (indent);
location = p->locus;
p = p->next;
if (t != NULL)
{
- if (t->list_p ())
+ if (TREE_CODE (t->tldcl) == TEMPLATE_FOR_STMT)
+ pp_verbatim (pp,
+ recursive_p
+ ? G_("recursively required from %<template for%> "
+ "iteration %E\n")
+ : G_("required from %<template for%> iteration %E\n"),
+ TREE_VEC_ELT (t->targs, 0));
+ else if (t->list_p ())
pp_verbatim (pp,
recursive_p
? G_("recursively required by substitution of %qS\n")
detected elsewhere. */
else if (VAR_P (old)
&& old_scope == current_binding_level->level_chain
- && (old_scope->kind == sk_cond || old_scope->kind == sk_for))
+ && (old_scope->kind == sk_cond
+ || old_scope->kind == sk_for
+ || old_scope->kind == sk_template_for))
{
if (name_independent_decl_p (decl))
return old;
"try-scope",
"catch-scope",
"for-scope",
+ "template-for-scope",
"cond-init-scope",
"stmt-expr-scope",
"function-parameter-scope",
case sk_try:
case sk_catch:
case sk_for:
+ case sk_template_for:
case sk_cond:
case sk_class:
case sk_scoped_enum:
sk_catch, /* A catch-block. */
sk_for, /* The scope of the variable declared in a
init-statement. */
+ sk_template_for, /* Ditto for expansion statements. */
sk_cond, /* The scope of the variable declared in the condition
of an if or switch statement. */
sk_stmt_expr, /* GNU statement expression block. */
/* The kind of scope that this object represents. However, a
SK_TEMPLATE_SPEC scope is represented with KIND set to
SK_TEMPLATE_PARMS and EXPLICIT_SPEC_P set to true. */
- ENUM_BITFIELD (scope_kind) kind : 4;
+ ENUM_BITFIELD (scope_kind) kind : 5;
/* True if this scope is an SK_TEMPLATE_SPEC scope. This field is
only valid if KIND == SK_TEMPLATE_PARMS. */
parent scope. */
unsigned artificial : 1;
- /* 21 bits left to fill a 32-bit word. */
+ /* 20 bits left to fill a 32-bit word. */
};
/* The binding level currently in effect. */
parser->in_template_argument_list_p);
cp_debug_print_flag (file, "Parsing an iteration statement",
parser->in_statement & IN_ITERATION_STMT);
+ cp_debug_print_flag (file, "Parsing an expansion statement",
+ parser->in_statement & IN_EXPANSION_STMT);
cp_debug_print_flag (file, "Parsing a switch statement",
parser->in_statement & IN_SWITCH_STMT);
cp_debug_print_flag (file, "Parsing a structured OpenMP block",
static tree cp_parser_range_for
(cp_parser *, tree, tree, tree, bool, tree, bool, bool);
static void do_range_for_auto_deduction
- (tree, tree, cp_decomp *);
-static tree cp_parser_perform_range_for_lookup
- (tree, tree *, tree *);
-static tree cp_parser_range_for_member_function
+ (tree, tree, cp_decomp *, bool);
+static tree cp_range_for_member_function
(tree, tree);
+static tree cp_parser_expansion_statement
+ (cp_parser *, bool *);
static tree cp_parser_jump_statement
(cp_parser *, tree &);
static void cp_parser_declaration_statement
bool save_in_consteval_if_p = in_consteval_if_p;
in_consteval_if_p = false;
+ /* Similarly the body of a lambda is not part of expansion statement. */
+ bool save_in_expansion_stmt = in_expansion_stmt;
+ in_expansion_stmt = 0;
+
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
finish_struct (type, /*attributes=*/NULL_TREE);
+ in_expansion_stmt = save_in_expansion_stmt;
in_consteval_if_p = save_in_consteval_if_p;
in_discarded_stmt = discarded;
case RID_TRANSACTION_CANCEL:
handle_omp_attribs = true;
break;
+ case RID_TEMPLATE:
+ if (cxx_dialect >= cxx11
+ && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR))
+ handle_omp_attribs = true;
+ break;
default:
break;
}
NULL_TREE, false);
break;
+ case RID_TEMPLATE:
+ if (cxx_dialect >= cxx11
+ && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR))
+ {
+ std_attrs = process_stmt_hotness_attribute (std_attrs,
+ attrs_loc);
+ statement = cp_parser_expansion_statement (parser, if_p);
+ }
+ break;
+
case RID_BREAK:
case RID_CONTINUE:
case RID_RETURN:
default:
/* Anything else must be an ordinary label. */
cp_expr identifier = cp_parser_identifier (parser);
+ if (in_expansion_stmt && identifier != error_mark_node)
+ {
+ error_at (token->location,
+ "identifier label %qE in %<template for%> body",
+ *identifier);
+ break;
+ }
if (identifier != error_mark_node
&& parser->omp_metadirective_state)
*identifier = mangle_metadirective_region_label (parser, *identifier);
return stmt;
}
+/* Helper function for cp_parser_range_for and cp_parser_expansion_statement.
+ Get the range declaration momentarily out of the way so that the range
+ expression doesn't clash with it. */
+
+static cp_decomp *
+cp_hide_range_decl (tree *range_decl_p, cp_decomp *decomp_d,
+ auto_vec <cxx_binding *> &bindings,
+ auto_vec <tree> &names)
+{
+ tree range_decl = *range_decl_p;
+ cp_decomp *decomp = NULL;
+ if (range_decl == error_mark_node)
+ return decomp;
+
+ if (DECL_HAS_VALUE_EXPR_P (range_decl))
+ {
+ tree v = DECL_VALUE_EXPR (range_decl);
+ /* For decomposition declaration get all of the corresponding
+ declarations out of the way. */
+ if ((TREE_CODE (v) == ARRAY_REF
+ && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+ || (TREE_CODE (v) == TREE_VEC
+ && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))))
+ {
+ tree d = range_decl;
+ decomp = decomp_d;
+ if (TREE_CODE (v) == ARRAY_REF)
+ {
+ *range_decl_p = range_decl = TREE_OPERAND (v, 0);
+ decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+ }
+ else
+ {
+ *range_decl_p = range_decl = TREE_VEC_ELT (v, 0);
+ decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1;
+ }
+ decomp->decl = d;
+ bool seen_name_independent_decl = false;
+ names.reserve (decomp->count);
+ bindings.reserve (decomp->count);
+ for (unsigned int i = 0; i < decomp->count; i++, d = DECL_CHAIN (d))
+ {
+ if (name_independent_decl_p (d))
+ {
+ /* If there is more than one _ decl in the structured
+ binding, just push and move it away once. */
+ if (seen_name_independent_decl)
+ continue;
+ seen_name_independent_decl = true;
+ }
+ tree name = DECL_NAME (d);
+ names.quick_push (name);
+ bindings.quick_push (IDENTIFIER_BINDING (name));
+ IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
+ }
+ }
+ }
+ if (names.is_empty ())
+ {
+ tree name = DECL_NAME (range_decl);
+ names.safe_push (name);
+ bindings.safe_push (IDENTIFIER_BINDING (name));
+ IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
+ }
+ return decomp;
+}
+
/* Tries to parse a range-based for-statement:
range-based-for:
bool ivdep, tree unroll, bool novector, bool is_omp)
{
tree stmt, range_expr;
- auto_vec <cxx_binding *, 16> bindings;
- auto_vec <tree, 16> names;
- cp_decomp decomp_d, *decomp = NULL;
+ auto_vec <cxx_binding *> bindings;
+ auto_vec <tree> names;
+ cp_decomp decomp_d;
/* Get the range declaration momentarily out of the way so that
the range expression doesn't clash with it. */
- if (range_decl != error_mark_node)
- {
- if (DECL_HAS_VALUE_EXPR_P (range_decl))
- {
- tree v = DECL_VALUE_EXPR (range_decl);
- /* For decomposition declaration get all of the corresponding
- declarations out of the way. */
- if ((TREE_CODE (v) == ARRAY_REF
- && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
- || (TREE_CODE (v) == TREE_VEC
- && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))))
- {
- tree d = range_decl;
- decomp = &decomp_d;
- if (TREE_CODE (v) == ARRAY_REF)
- {
- range_decl = TREE_OPERAND (v, 0);
- decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
- }
- else
- {
- range_decl = TREE_VEC_ELT (v, 0);
- decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1;
- }
- decomp->decl = d;
- bool seen_name_independent_decl = false;
- for (unsigned int i = 0; i < decomp->count;
- i++, d = DECL_CHAIN (d))
- {
- if (name_independent_decl_p (d))
- {
- /* If there is more than one _ decl in
- the structured binding, just push and move it
- away once. */
- if (seen_name_independent_decl)
- continue;
- seen_name_independent_decl = true;
- }
- tree name = DECL_NAME (d);
- names.safe_push (name);
- bindings.safe_push (IDENTIFIER_BINDING (name));
- IDENTIFIER_BINDING (name)
- = IDENTIFIER_BINDING (name)->previous;
- }
- }
- }
- if (names.is_empty ())
- {
- tree name = DECL_NAME (range_decl);
- names.safe_push (name);
- bindings.safe_push (IDENTIFIER_BINDING (name));
- IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
- }
- }
+ cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings,
+ names);
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
range_expr = cp_parser_braced_list (parser);
if (!type_dependent_expression_p (range_expr)
/* do_auto_deduction doesn't mess with template init-lists. */
&& !BRACE_ENCLOSED_INITIALIZER_P (range_expr))
- do_range_for_auto_deduction (range_decl, range_expr, decomp);
+ do_range_for_auto_deduction (range_decl, range_expr, decomp, false);
}
else
{
/* Subroutine of cp_convert_range_for: given the initializer expression,
builds up the range temporary. */
-static tree
+tree
build_range_temp (tree range_expr)
{
/* Find out the type deduced by the declaration
a shortcut version of cp_convert_range_for. */
static void
-do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp)
+do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp,
+ bool expansion_stmt)
{
tree auto_node = type_uses_auto (TREE_TYPE (decl));
if (auto_node)
{
tree begin_dummy, end_dummy, range_temp, iter_type, iter_decl;
range_temp = convert_from_reference (build_range_temp (range_expr));
- iter_type = (cp_parser_perform_range_for_lookup
- (range_temp, &begin_dummy, &end_dummy));
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_dummy,
+ &end_dummy,
+ expansion_stmt ? tf_none
+ : tf_warning_or_error);
+ if (expansion_stmt
+ && (begin_dummy == error_mark_node
+ || end_dummy == error_mark_node))
+ return;
if (iter_type)
{
iter_decl = build_decl (input_location, VAR_DECL, NULL_TREE,
}
}
+/* Helper function for cp_convert_range_for and finish_expansion_stmt.
+ Build the __range, __begin and __end declarations. Return the
+ __begin VAR_DECL, set *END_P to the __end VAR_DECL. */
+
+tree
+cp_build_range_for_decls (location_t loc, tree range_expr, tree *end_p,
+ bool expansion_stmt_p)
+{
+ tree iter_type, begin_expr, end_expr;
+
+ if (range_expr == error_mark_node)
+ /* If an error happened previously do nothing or else a lot of
+ unhelpful errors would be issued. */
+ begin_expr = end_expr = iter_type = error_mark_node;
+ else
+ {
+ tree range_temp;
+
+ if (!expansion_stmt_p
+ && VAR_P (range_expr)
+ && array_of_runtime_bound_p (TREE_TYPE (range_expr)))
+ /* Can't bind a reference to an array of runtime bound. */
+ range_temp = range_expr;
+ else
+ {
+ range_temp = build_range_temp (range_expr);
+ if (expansion_stmt_p)
+ {
+ /* Depending on CWG3044 resolution, we might want to remove
+ these 3 sets of TREE_STATIC (on range_temp, begin and end).
+ Although it can only be done when P2686R4 is fully
+ implemented. */
+ TREE_STATIC (range_temp) = 1;
+ TREE_PUBLIC (range_temp) = 0;
+ DECL_COMMON (range_temp) = 0;
+ DECL_INTERFACE_KNOWN (range_temp) = 1;
+ DECL_DECLARED_CONSTEXPR_P (range_temp) = 1;
+ TREE_READONLY (range_temp) = 1;
+ }
+ pushdecl (range_temp);
+ cp_finish_decl (range_temp, range_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ range_temp = convert_from_reference (range_temp);
+ }
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
+ &end_expr);
+ }
+
+ /* The new for initialization statement. */
+ tree begin = build_decl (loc, VAR_DECL, for_begin__identifier, iter_type);
+ TREE_USED (begin) = 1;
+ DECL_ARTIFICIAL (begin) = 1;
+ if (expansion_stmt_p)
+ {
+ TREE_STATIC (begin) = 1;
+ DECL_DECLARED_CONSTEXPR_P (begin) = 1;
+ TREE_READONLY (begin) = 1;
+ }
+ pushdecl (begin);
+ cp_finish_decl (begin, begin_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+
+ if (cxx_dialect >= cxx17)
+ iter_type = cv_unqualified (TREE_TYPE (end_expr));
+ tree end = build_decl (loc, VAR_DECL, for_end__identifier, iter_type);
+ TREE_USED (end) = 1;
+ DECL_ARTIFICIAL (end) = 1;
+ if (expansion_stmt_p)
+ {
+ TREE_STATIC (end) = 1;
+ DECL_DECLARED_CONSTEXPR_P (end) = 1;
+ TREE_READONLY (end) = 1;
+ }
+ pushdecl (end);
+ cp_finish_decl (end, end_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ *end_p = end;
+ return begin;
+}
+
/* Converts a range-based for-statement into a normal
for-statement, as per the definition.
cp_decomp *decomp, bool ivdep, tree unroll,
bool novector)
{
- tree begin, end;
- tree iter_type, begin_expr, end_expr;
- tree condition, expression;
+ tree end, condition, expression;
range_expr = mark_lvalue_use (range_expr);
- if (range_decl == error_mark_node || range_expr == error_mark_node)
- /* If an error happened previously do nothing or else a lot of
- unhelpful errors would be issued. */
- begin_expr = end_expr = iter_type = error_mark_node;
- else
- {
- tree range_temp;
-
- if (VAR_P (range_expr)
- && array_of_runtime_bound_p (TREE_TYPE (range_expr)))
- /* Can't bind a reference to an array of runtime bound. */
- range_temp = range_expr;
- else
- {
- range_temp = build_range_temp (range_expr);
- pushdecl (range_temp);
- cp_finish_decl (range_temp, range_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
- range_temp = convert_from_reference (range_temp);
- }
- iter_type = cp_parser_perform_range_for_lookup (range_temp,
- &begin_expr, &end_expr);
- }
-
- /* The new for initialization statement. */
- begin = build_decl (input_location, VAR_DECL, for_begin__identifier,
- iter_type);
- TREE_USED (begin) = 1;
- DECL_ARTIFICIAL (begin) = 1;
- pushdecl (begin);
- cp_finish_decl (begin, begin_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
-
- if (cxx_dialect >= cxx17)
- iter_type = cv_unqualified (TREE_TYPE (end_expr));
- end = build_decl (input_location, VAR_DECL, for_end__identifier, iter_type);
- TREE_USED (end) = 1;
- DECL_ARTIFICIAL (end) = 1;
- pushdecl (end);
- cp_finish_decl (end, end_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
+ if (range_decl == error_mark_node)
+ range_expr = error_mark_node;
+ tree begin
+ = cp_build_range_for_decls (input_location, range_expr, &end, false);
finish_init_stmt (statement);
depends on the existence of members begin or end.
Returns the type deduced for the iterator expression. */
-static tree
-cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
+tree
+cp_perform_range_for_lookup (tree range, tree *begin, tree *end,
+ tsubst_flags_t complain
+ /* = tf_warning_or_error */)
{
if (error_operand_p (range))
{
if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (range))))
{
- error ("range-based %<for%> expression of type %qT "
- "has incomplete type", TREE_TYPE (range));
+ if (complain & tf_error)
+ error ("range-based %<for%> expression of type %qT "
+ "has incomplete type", TREE_TYPE (range));
*begin = *end = error_mark_node;
return error_mark_node;
}
id_end = get_identifier ("end");
member_begin = lookup_member (TREE_TYPE (range), id_begin,
/*protect=*/2, /*want_type=*/false,
- tf_warning_or_error);
+ complain);
member_end = lookup_member (TREE_TYPE (range), id_end,
/*protect=*/2, /*want_type=*/false,
- tf_warning_or_error);
+ complain);
if (member_begin != NULL_TREE && member_end != NULL_TREE)
{
/* Use the member functions. */
- *begin = cp_parser_range_for_member_function (range, id_begin);
- *end = cp_parser_range_for_member_function (range, id_end);
+ *begin = cp_range_for_member_function (range, id_begin);
+ *end = cp_range_for_member_function (range, id_end);
}
else
{
vec_safe_push (vec, range);
member_begin = perform_koenig_lookup (id_begin, vec,
- tf_warning_or_error);
+ complain);
+ if ((complain & tf_error) == 0 && member_begin == id_begin)
+ return error_mark_node;
*begin = finish_call_expr (member_begin, &vec, false, true,
- tf_warning_or_error);
+ complain);
member_end = perform_koenig_lookup (id_end, vec,
tf_warning_or_error);
+ if ((complain & tf_error) == 0 && member_end == id_end)
+ {
+ *begin = error_mark_node;
+ return error_mark_node;
+ }
*end = finish_call_expr (member_end, &vec, false, true,
- tf_warning_or_error);
+ complain);
}
/* Last common checks. */
/* P0184R0 allows __begin and __end to have different types,
but make sure they are comparable so we can give a better
diagnostic. */;
- else
+ else if (complain & tf_error)
error ("inconsistent begin/end types in range-based %<for%> "
"statement: %qT and %qT",
TREE_TYPE (*begin), TREE_TYPE (*end));
}
}
-/* Helper function for cp_parser_perform_range_for_lookup.
+/* Helper function for cp_perform_range_for_lookup.
Builds a tree for RANGE.IDENTIFIER(). */
static tree
-cp_parser_range_for_member_function (tree range, tree identifier)
+cp_range_for_member_function (tree range, tree identifier)
{
tree member, res;
return false;
}
+/* Parse an expansion-statement.
+
+ expansion-statement:
+ template for ( init-statement[opt]
+ for-range-declaration : expansion-initializer )
+ statement
+
+ expansion-initializer:
+ expression
+ expansion-init-list
+
+ expansion-init-list:
+ { expression-list } */
+
+static tree
+cp_parser_expansion_statement (cp_parser* parser, bool *if_p)
+{
+ /* Peek at the next token. */
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ gcc_assert (token->keyword == RID_TEMPLATE);
+ gcc_assert (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR));
+ cp_lexer_consume_token (parser->lexer);
+ cp_token *for_token = cp_lexer_peek_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+
+ if (cxx_dialect < cxx26)
+ pedwarn (make_location (token->location, token->location,
+ for_token->location), OPT_Wc__26_extensions,
+ "%<template for%> only available with %<-std=c++2c%> "
+ "or %<-std=gnu++2c%>");
+
+ token_indent_info guard_tinfo = get_token_indent_info (token);
+
+ /* Remember whether or not we are already within an iteration
+ statement. */
+ unsigned char in_statement = parser->in_statement;
+ /* And whether we are already in expansion-statement. */
+ auto save_in_expansion_stmt = in_expansion_stmt;
+
+ /* Look for the `('. */
+ matching_parens parens;
+ parens.require_open (parser);
+
+ tree init;
+ tree scope = begin_template_for_scope (&init);
+
+ /* Maybe parse the optional init-statement in a expansion-statement. */
+ if (cp_parser_range_based_for_with_init_p (parser)
+ /* Checked for diagnostic purposes only. */
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ {
+ tree dummy;
+ cp_parser_init_statement (parser, &dummy);
+ }
+
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+
+ /* A colon is used in expansion-statement. */
+ parser->colon_corrects_to_scope_p = false;
+
+ /* Parse the declaration. */
+ tree range_decl;
+ cp_parser_simple_declaration (parser,
+ /*function_definition_allowed_p=*/false,
+ &range_decl);
+ if (range_decl == NULL_TREE)
+ range_decl = error_mark_node;
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+
+ auto_vec <cxx_binding *> bindings;
+ auto_vec <tree> names;
+ cp_decomp decomp_d;
+
+ /* Get the range declaration momentarily out of the way so that
+ the range expression doesn't clash with it. */
+ cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings,
+ names);
+
+ tree expansion_init;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ expansion_init = cp_parser_braced_list (parser);
+ if (TREE_CODE (expansion_init) == CONSTRUCTOR
+ && CONSTRUCTOR_IS_DESIGNATED_INIT (expansion_init))
+ error_at (EXPR_LOC_OR_LOC (expansion_init, token->location),
+ "designators in %<template for%> initializer");
+ }
+ else
+ expansion_init = cp_parser_expression (parser);
+
+ /* Put the range declaration(s) back into scope. */
+ for (unsigned int i = 0; i < names.length (); i++)
+ {
+ cxx_binding *binding = bindings[i];
+ binding->previous = IDENTIFIER_BINDING (names[i]);
+ IDENTIFIER_BINDING (names[i]) = binding;
+ }
+
+ /* Look for the `)'. */
+ parens.require_close (parser);
+
+ if (processing_template_decl
+ && check_for_bare_parameter_packs (expansion_init))
+ expansion_init = error_mark_node;
+
+ if (expansion_init != error_mark_node
+ && !type_dependent_expression_p (expansion_init)
+ && TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE
+ && !BRACE_ENCLOSED_INITIALIZER_P (expansion_init))
+ do_range_for_auto_deduction (range_decl, expansion_init, decomp,
+ true);
+
+ bool outside_of_template = !processing_template_decl;
+ if (outside_of_template)
+ {
+ ++processing_template_decl;
+ current_template_parms
+ = tree_cons (size_int (current_template_depth + 1),
+ make_tree_vec (0), current_template_parms);
+ }
+ in_expansion_stmt = true;
+
+ tree r = build_stmt (token->location, TEMPLATE_FOR_STMT, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+
+ current_binding_level->this_entity = r;
+ TEMPLATE_FOR_INIT_STMT (r) = init;
+ TEMPLATE_FOR_SCOPE (r) = scope;
+ if (!outside_of_template)
+ TEMPLATE_FOR_INIT_STMT (r) = pop_stmt_list (TEMPLATE_FOR_INIT_STMT (r));
+ TEMPLATE_FOR_DECL (r) = range_decl;
+ TEMPLATE_FOR_EXPR (r) = expansion_init;
+ TEMPLATE_FOR_BODY (r) = do_pushlevel (sk_block);
+
+ /* Parse the body of the expansion-statement. */
+ parser->in_statement = IN_EXPANSION_STMT;
+ bool prev = note_iteration_stmt_body_start ();
+ cp_parser_already_scoped_statement (parser, if_p, guard_tinfo);
+ note_iteration_stmt_body_end (prev);
+ parser->in_statement = in_statement;
+ in_expansion_stmt = save_in_expansion_stmt;
+
+ TEMPLATE_FOR_BODY (r) = do_poplevel (TEMPLATE_FOR_BODY (r));
+
+ if (outside_of_template)
+ {
+ current_template_parms = TREE_CHAIN (current_template_parms);
+ --processing_template_decl;
+ }
+
+ if (VAR_P (range_decl) && DECL_DECLARED_CONSTINIT_P (range_decl))
+ error_at (DECL_SOURCE_LOCATION (range_decl),
+ "for-range-declaration cannot be 'constinit'");
+
+ if (decomp)
+ {
+ tree v = make_tree_vec (decomp->count + 1);
+ TREE_VEC_ELT (v, 0) = TEMPLATE_FOR_DECL (r);
+ tree d = decomp->decl;
+ for (unsigned i = 0; i < decomp->count; ++i, d = DECL_CHAIN (d))
+ TREE_VEC_ELT (v, decomp->count - i) = d;
+ TEMPLATE_FOR_DECL (r) = v;
+ }
+
+ if (processing_template_decl)
+ add_stmt (r);
+ else
+ finish_expansion_stmt (r, NULL_TREE, tf_warning_or_error, NULL_TREE);
+
+ add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (r)));
+ TEMPLATE_FOR_SCOPE (r) = NULL_TREE;
+
+ return r;
+}
+
/* Parse a jump-statement.
jump-statement:
break;
default:
gcc_assert ((in_statement & IN_SWITCH_STMT)
- || in_statement == IN_ITERATION_STMT);
+ || in_statement == IN_ITERATION_STMT
+ || in_statement == IN_EXPANSION_STMT);
statement = finish_break_stmt ();
if (in_statement == IN_ITERATION_STMT)
break_maybe_infinite_loop ();
break;
/* Fall through. */
case IN_ITERATION_STMT:
+ case IN_EXPANSION_STMT:
case IN_OMP_FOR:
statement = finish_continue_stmt ();
break;
decomp->decl = decl;
}
}
- do_range_for_auto_deduction (d, init, decomp);
+ do_range_for_auto_deduction (d, init, decomp, false);
}
cond = global_namespace;
incr = NULL_TREE;
range_temp_decl = range_temp;
range_temp = convert_from_reference (range_temp);
}
- iter_type = cp_parser_perform_range_for_lookup (range_temp,
- &begin_expr, &end_expr);
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
+ &end_expr);
}
tree end_iter_type = iter_type;
/* Set to IN_ITERATION_STMT if parsing an iteration-statement,
to IN_OMP_BLOCK if parsing OpenMP structured block and
- IN_OMP_FOR if parsing OpenMP loop. If parsing a switch statement,
+ IN_OMP_FOR if parsing OpenMP loop, IN_EXPANSION_STMT if parsing an
+ expansion-statement. If parsing a switch statement,
this is bitwise ORed with IN_SWITCH_STMT, unless parsing an
iteration-statement, OpenMP block or loop within that switch. */
#define IN_SWITCH_STMT 1
#define IN_ITERATION_STMT 2
#define IN_OMP_BLOCK 4
#define IN_OMP_FOR 8
-#define IN_IF_STMT 16
+#define IN_IF_STMT 16
+#define IN_EXPANSION_STMT 32
unsigned char in_statement;
/* TRUE if we are presently parsing the body of a switch statement.
#pragma GCC diagnostic ignored "-Wformat-diag"
#endif
bool list_p = new_level->list_p ();
- if (list_p && !pp.has_flag (TDF_DETAILS))
+ if ((list_p || TREE_CODE (tldcl) == TEMPLATE_FOR_STMT)
+ && !pp.has_flag (TDF_DETAILS))
/* Skip non-instantiations unless -details. */;
else
{
}
for (int i = 0; i < tinst_depth; ++i)
pp_space (&pp);
- if (list_p)
+ if (TREE_CODE (tldcl) == TEMPLATE_FOR_STMT)
+ pp_printf (&pp, "I template for");
+ else if (list_p)
pp_printf (&pp, "S %S", new_level->get_node ());
else
pp_printf (&pp, "I %D", tldcl);
{
last_ctx = ctx;
pp_newline (&pp);
- if (t->list_p ())
+ if (TREE_CODE (t->tldcl) == TEMPLATE_FOR_STMT)
+ pp_printf (&pp, "RI template for");
+ else if (t->list_p ())
pp_printf (&pp, "RS %S", ctx);
else
pp_printf (&pp, "RI %D", ctx);
finish_do_stmt (tmp, stmt, false, 0, false);
break;
+ case TEMPLATE_FOR_STMT:
+ {
+ tree init;
+ stmt = build_stmt (EXPR_LOCATION (t), TEMPLATE_FOR_STMT, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+ TEMPLATE_FOR_SCOPE (stmt) = begin_template_for_scope (&init);
+ TEMPLATE_FOR_INIT_STMT (stmt) = init;
+ RECUR (TEMPLATE_FOR_INIT_STMT (t));
+ TEMPLATE_FOR_EXPR (stmt) = RECUR (TEMPLATE_FOR_EXPR (t));
+ if (processing_template_decl)
+ {
+ tree orig_decl = TEMPLATE_FOR_DECL (t);
+ if (TREE_CODE (orig_decl) == TREE_VEC)
+ orig_decl = TREE_VEC_ELT (orig_decl, 0);
+ tree decl = tsubst (orig_decl, args, complain, in_decl);
+ maybe_push_decl (decl);
+
+ cp_decomp decomp_d, *decomp = NULL;
+ if (DECL_DECOMPOSITION_P (decl))
+ {
+ decomp = &decomp_d;
+ decl = tsubst_decomp_names (decl, orig_decl, args,
+ complain, in_decl, decomp);
+ if (decl != error_mark_node)
+ {
+ tree v = make_tree_vec (decomp->count + 1);
+ TREE_VEC_ELT (v, 0) = decl;
+ decl = decomp->decl;
+ for (unsigned i = 0; i < decomp->count; ++i)
+ {
+ TREE_VEC_ELT (v, decomp->count - i) = decl;
+ decl = DECL_CHAIN (decl);
+ }
+ decl = v;
+ }
+ }
+ TEMPLATE_FOR_DECL (stmt) = decl;
+ TEMPLATE_FOR_INIT_STMT (stmt) = pop_stmt_list (init);
+ add_stmt (stmt);
+ TEMPLATE_FOR_BODY (stmt) = do_pushlevel (sk_block);
+ bool prev = note_iteration_stmt_body_start ();
+ RECUR (TEMPLATE_FOR_BODY (t));
+ note_iteration_stmt_body_end (prev);
+ TEMPLATE_FOR_BODY (stmt)
+ = do_poplevel (TEMPLATE_FOR_BODY (stmt));
+ }
+ else
+ {
+ TEMPLATE_FOR_DECL (stmt) = TEMPLATE_FOR_DECL (t);
+ TEMPLATE_FOR_BODY (stmt) = TEMPLATE_FOR_BODY (t);
+ finish_expansion_stmt (stmt, args, complain, in_decl);
+ }
+ add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (stmt)));
+ }
+ break;
+
case IF_STMT:
stmt = begin_if_stmt ();
IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t);
}
}
+struct expansion_stmt_bc
+{
+ tree break_label;
+ tree continue_label;
+ hash_set<tree> *pset;
+ location_t loc;
+ bool in_switch;
+};
+
+/* Helper function for finish_expansion_stmt. Find BREAK_STMT (not
+ nested inside of other WHILE_STMT, FOR_STMT, DO_STMT, TEMPLATE_FOR_STMT
+ or SWITCH_STMT) or CONTINUE_STMT (not nested inside those except
+ perhaps SWITCH_STMT) and replace them with GOTO_EXPR to lazily created
+ label. */
+
+static tree
+expansion_stmt_find_bc_r (tree *tp, int *walk_subtrees, void *data)
+{
+ tree t = *tp;
+ expansion_stmt_bc *bc_data = (expansion_stmt_bc *) data;
+ switch (TREE_CODE (t))
+ {
+ case WHILE_STMT:
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (WHILE_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &WHILE_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ break;
+ case FOR_STMT:
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (FOR_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &FOR_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ break;
+ case DO_STMT:
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (DO_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &DO_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ break;
+ case TEMPLATE_FOR_STMT:
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (TEMPLATE_FOR_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &TEMPLATE_FOR_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ break;
+ case SWITCH_STMT:
+ if (!bc_data->in_switch)
+ {
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (SWITCH_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &SWITCH_STMT_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ bc_data->in_switch = true;
+ cp_walk_tree (&SWITCH_STMT_BODY (t), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ bc_data->in_switch = false;
+ }
+ break;
+ case BREAK_STMT:
+ if (!bc_data->in_switch)
+ {
+ if (!bc_data->break_label)
+ {
+ bc_data->break_label = create_artificial_label (bc_data->loc);
+ TREE_USED (bc_data->break_label) = 1;
+ LABEL_DECL_BREAK (bc_data->break_label) = true;
+ }
+ *tp = build1_loc (EXPR_LOCATION (t), GOTO_EXPR, void_type_node,
+ bc_data->break_label);
+ }
+ break;
+ case CONTINUE_STMT:
+ if (!bc_data->continue_label)
+ {
+ bc_data->continue_label = create_artificial_label (bc_data->loc);
+ TREE_USED (bc_data->continue_label) = 1;
+ LABEL_DECL_CONTINUE (bc_data->continue_label) = true;
+ }
+ *tp = build1_loc (EXPR_LOCATION (t), GOTO_EXPR, void_type_node,
+ bc_data->continue_label);
+ break;
+ default:
+ if (TYPE_P (t))
+ *walk_subtrees = 0;
+ break;
+ }
+ return NULL_TREE;
+}
+
+/* Finish an expansion-statement. */
+
+void
+finish_expansion_stmt (tree expansion_stmt, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree expansion_init = TEMPLATE_FOR_EXPR (expansion_stmt);
+ if (error_operand_p (expansion_init))
+ return;
+
+ enum expansion_stmt_kind {
+ esk_none,
+ esk_iterating,
+ esk_destructuring,
+ esk_enumerating
+ } kind = esk_none;
+
+ unsigned HOST_WIDE_INT n = 0;
+ tree range_decl = TEMPLATE_FOR_DECL (expansion_stmt);
+ bool is_decomp = false;
+ if (TREE_CODE (range_decl) == TREE_VEC)
+ {
+ is_decomp = true;
+ range_decl = TREE_VEC_ELT (range_decl, 0);
+ }
+ if (error_operand_p (range_decl))
+ return;
+
+ location_t loc = DECL_SOURCE_LOCATION (range_decl);
+ tree begin = NULL_TREE;
+ auto_vec<tree, 8> destruct_decls;
+ if (BRACE_ENCLOSED_INITIALIZER_P (expansion_init))
+ {
+ /* Enumerating expansion statements. */
+ kind = esk_enumerating;
+ n = CONSTRUCTOR_NELTS (expansion_init);
+ }
+ else if (TYPE_REF_P (TREE_TYPE (expansion_init))
+ ? TREE_CODE (TREE_TYPE (TREE_TYPE (expansion_init))) != ARRAY_TYPE
+ : TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE)
+ {
+ tree range_temp, begin_expr, end_expr, iter_type;
+ range_temp = convert_from_reference (build_range_temp (expansion_init));
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
+ &end_expr, tf_none);
+ if (begin_expr != error_mark_node && end_expr != error_mark_node)
+ {
+ kind = esk_iterating;
+ gcc_assert (iter_type);
+ }
+ }
+ if (kind == esk_iterating)
+ {
+ /* Iterating expansion statements. */
+ tree end;
+ begin = cp_build_range_for_decls (loc, expansion_init, &end, true);
+ if (!error_operand_p (begin) && !error_operand_p (end))
+ {
+ tree i = get_target_expr (begin);
+ tree w = build_stmt (loc, WHILE_STMT, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE);
+ tree r = get_target_expr (build_zero_cst (ptrdiff_type_node));
+ tree iinc = build_x_unary_op (loc, PREINCREMENT_EXPR,
+ TARGET_EXPR_SLOT (i), NULL_TREE,
+ tf_warning_or_error);
+ tree rinc = build2 (PREINCREMENT_EXPR, ptrdiff_type_node,
+ TARGET_EXPR_SLOT (r),
+ build_int_cst (ptrdiff_type_node, 1));
+ WHILE_BODY (w) = build_compound_expr (loc, iinc, rinc);
+ WHILE_COND (w) = build_x_binary_op (loc, NE_EXPR, i, ERROR_MARK,
+ end, ERROR_MARK, NULL_TREE, NULL,
+ tf_warning_or_error);
+ tree e = build_compound_expr (loc, r, i);
+ e = build_compound_expr (loc, e, w);
+ e = build_compound_expr (loc, e, TARGET_EXPR_SLOT (r));
+ e = cxx_constant_value (e);
+ if (tree_fits_uhwi_p (e))
+ n = tree_to_uhwi (e);
+ }
+ }
+ else if (kind == esk_none)
+ {
+ kind = esk_destructuring;
+ HOST_WIDE_INT sz = cp_decomp_size (loc, TREE_TYPE (expansion_init),
+ tf_warning_or_error);
+ if (sz < 0)
+ return;
+ if (sz == 0)
+ {
+ error_at (loc, "empty structured binding");
+ return;
+ }
+ n = sz;
+ tree auto_node = make_auto ();
+ tree decomp_type = cp_build_reference_type (auto_node, true);
+ decomp_type = do_auto_deduction (decomp_type, expansion_init, auto_node);
+ tree decl = build_decl (loc, VAR_DECL, NULL_TREE, decomp_type);
+ TREE_USED (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_DECLARED_CONSTEXPR_P (decl)
+ = DECL_DECLARED_CONSTEXPR_P (range_decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ TREE_READONLY (decl) = 1;
+ fit_decomposition_lang_decl (decl, NULL_TREE);
+ pushdecl (decl);
+ cp_decomp this_decomp;
+ this_decomp.count = n;
+ destruct_decls.safe_grow (n, true);
+ for (unsigned HOST_WIDE_INT i = 0; i < n; ++i)
+ {
+ tree this_decl = build_decl (loc, VAR_DECL, NULL_TREE, make_auto ());
+ TREE_USED (this_decl) = 1;
+ DECL_ARTIFICIAL (this_decl) = 1;
+ DECL_DECLARED_CONSTEXPR_P (this_decl)
+ = DECL_DECLARED_CONSTEXPR_P (decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ TREE_READONLY (this_decl) = 1;
+ pushdecl (this_decl);
+ this_decomp.decl = this_decl;
+ destruct_decls[i] = this_decl;
+ }
+ DECL_NAME (decl) = for_range__identifier;
+ cp_finish_decl (decl, expansion_init,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING, &this_decomp);
+ DECL_NAME (decl) = NULL_TREE;
+ }
+
+ expansion_stmt_bc bc_data = { NULL_TREE, NULL_TREE, NULL, loc, false };
+
+ for (unsigned HOST_WIDE_INT i = 0; i < n; ++i)
+ {
+ tree scope = do_pushlevel (sk_block);
+ bool revert_outer
+ = (current_binding_level->level_chain
+ && current_binding_level->level_chain->kind == sk_template_for);
+ /* Don't diagnose redeclaration of for-range-declaration decls.
+ The sk_template_for block is reused for the originally parsed
+ source as well as the lowered one. In the original one
+ redeclaration of the for-range-declaration decls in the substatement
+ should be diagnosed (i.e. declarations of the same name in sk_block
+ of the body vs. declarations in sk_template_for block). In the
+ lowered case, the sk_block added by do_pushlevel (sk_block) above
+ will be block in the lowering of each Si. Those blocks do redeclare
+ for-range-declaration, so temporarily change sk_template_for
+ kind to sk_block to avoid it being diagnosed as invalid. */
+ if (revert_outer)
+ current_binding_level->level_chain->kind = sk_block;
+ tree type = TREE_TYPE (range_decl);
+ if (args)
+ type = tsubst (type, args, complain | tf_tst_ok, in_decl);
+ tree decl = build_decl (loc, VAR_DECL, DECL_NAME (range_decl), type);
+ DECL_ATTRIBUTES (decl) = DECL_ATTRIBUTES (range_decl);
+ if (args)
+ apply_late_template_attributes (&decl, DECL_ATTRIBUTES (decl),
+ /*flags=*/0, args, complain,
+ in_decl);
+
+ DECL_DECLARED_CONSTEXPR_P (decl)
+ = DECL_DECLARED_CONSTEXPR_P (range_decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ TREE_READONLY (decl) = 1;
+ pushdecl (decl);
+ tree init = NULL_TREE;
+ switch (kind)
+ {
+ case esk_enumerating:
+ init = CONSTRUCTOR_ELT (expansion_init, i)->value;
+ break;
+ case esk_iterating:
+ tree iter_init, auto_node, iter_type, iter;
+ iter_init
+ = build_x_binary_op (loc, PLUS_EXPR, begin, ERROR_MARK,
+ build_int_cst (ptrdiff_type_node, i),
+ ERROR_MARK, NULL_TREE, NULL,
+ tf_warning_or_error);
+ auto_node = make_auto ();
+ iter_type = do_auto_deduction (auto_node, iter_init, auto_node);
+ iter = build_decl (loc, VAR_DECL, NULL_TREE, iter_type);
+ TREE_USED (iter) = 1;
+ DECL_ARTIFICIAL (iter) = 1;
+ TREE_STATIC (iter) = 1;
+ DECL_DECLARED_CONSTEXPR_P (iter) = 1;
+ pushdecl (iter);
+ cp_finish_decl (iter, iter_init, /*is_constant_init*/false,
+ NULL_TREE, LOOKUP_ONLYCONVERTING);
+ init = build_x_indirect_ref (loc, iter, RO_UNARY_STAR, NULL_TREE,
+ tf_warning_or_error);
+ break;
+ case esk_destructuring:
+ init = convert_from_reference (destruct_decls[i]);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ cp_decomp this_decomp = {};
+ if (is_decomp)
+ {
+ fit_decomposition_lang_decl (decl, NULL_TREE);
+ tree v = TEMPLATE_FOR_DECL (expansion_stmt);
+ this_decomp.count = TREE_VEC_LENGTH (v) - 1;
+ for (unsigned i = 0; i < this_decomp.count; ++i)
+ {
+ tree this_decl
+ = build_decl (loc, VAR_DECL,
+ DECL_NAME (TREE_VEC_ELT (v, i + 1)),
+ make_auto ());
+ TREE_USED (this_decl) = 1;
+ DECL_ARTIFICIAL (this_decl) = 1;
+ DECL_ATTRIBUTES (this_decl)
+ = DECL_ATTRIBUTES (TREE_VEC_ELT (v, i + 1));
+ if (DECL_PACK_P (TREE_VEC_ELT (v, i + 1)))
+ {
+ tree dtype = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (dtype) = this_decl;
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1;
+ SET_TYPE_STRUCTURAL_EQUALITY (dtype);
+ tree type = cxx_make_type (TYPE_PACK_EXPANSION);
+ PACK_EXPANSION_PATTERN (type) = dtype;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ PACK_EXPANSION_PARAMETER_PACKS (type) = this_decl;
+ TREE_TYPE (this_decl) = type;
+ }
+ if (args)
+ apply_late_template_attributes (&this_decl,
+ DECL_ATTRIBUTES (this_decl),
+ /*flags=*/0, args,
+ complain, in_decl);
+ DECL_DECLARED_CONSTEXPR_P (this_decl)
+ = DECL_DECLARED_CONSTEXPR_P (decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ TREE_READONLY (this_decl) = 1;
+ pushdecl (this_decl);
+ this_decomp.decl = this_decl;
+ }
+ }
+ cp_finish_decl (decl, init, false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING, is_decomp ? &this_decomp : NULL);
+ if (revert_outer)
+ current_binding_level->level_chain->kind = sk_template_for;
+ tree targs = args;
+ if (args == NULL_TREE)
+ {
+ targs = make_tree_vec (1);
+ TREE_VEC_ELT (targs, 0) = build_int_cst (ptrdiff_type_node, i + 1);
+ }
+ if (args != NULL_TREE
+ || push_tinst_level_loc (expansion_stmt, targs, loc))
+ {
+ local_specialization_stack lss (lss_copy);
+ register_local_specialization (decl, range_decl);
+ if (is_decomp)
+ {
+ tree d = this_decomp.decl;
+ unsigned int cnt = this_decomp.count;
+ tree v = TEMPLATE_FOR_DECL (expansion_stmt);
+ for (unsigned int i = 0; i < cnt; ++i, d = DECL_CHAIN (d))
+ register_local_specialization (d, TREE_VEC_ELT (v, cnt - i));
+ }
+ tsubst_stmt (TEMPLATE_FOR_BODY (expansion_stmt),
+ targs, complain, in_decl ? in_decl : range_decl);
+ if (args == NULL_TREE)
+ pop_tinst_level ();
+ }
+ tree stmt = do_poplevel (scope);
+ if (stmt)
+ {
+ add_stmt (stmt);
+ hash_set<tree> pset;
+ bc_data.continue_label = NULL_TREE;
+ bc_data.pset = &pset;
+ cp_walk_tree (&stmt, expansion_stmt_find_bc_r, &bc_data, &pset);
+ if (bc_data.continue_label)
+ add_stmt (build1 (LABEL_EXPR, void_type_node,
+ bc_data.continue_label));
+ }
+ }
+ if (bc_data.break_label)
+ add_stmt (build1 (LABEL_EXPR, void_type_node, bc_data.break_label));
+ if (args == NULL_TREE)
+ {
+ TREE_TYPE (range_decl) = error_mark_node;
+ if (DECL_HAS_VALUE_EXPR_P (range_decl))
+ {
+ SET_DECL_VALUE_EXPR (range_decl, NULL_TREE);
+ DECL_HAS_VALUE_EXPR_P (range_decl) = 0;
+ }
+ if (is_decomp)
+ {
+ tree v = TEMPLATE_FOR_DECL (expansion_stmt);
+ for (int i = 1; i < TREE_VEC_LENGTH (v); ++i)
+ {
+ tree d = TREE_VEC_ELT (v, i);
+ TREE_TYPE (d) = error_mark_node;
+ if (DECL_HAS_VALUE_EXPR_P (d))
+ {
+ SET_DECL_VALUE_EXPR (d, NULL_TREE);
+ DECL_HAS_VALUE_EXPR_P (d) = 0;
+ }
+ }
+ }
+ }
+}
+
/* Set up the hash tables for template instantiations. */
void
/* Begin a new scope. */
-static tree
+tree
do_pushlevel (scope_kind sk)
{
tree ret = push_stmt_list ();
RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block);
}
+/* Begin the scope of an expansion-statement. */
+
+tree
+begin_template_for_scope (tree *init)
+{
+ tree scope = do_pushlevel (sk_template_for);
+
+ if (processing_template_decl)
+ *init = push_stmt_list ();
+ else
+ *init = NULL_TREE;
+
+ return scope;
+}
+
/* Finish a break-statement. */
tree
--- /dev/null
+// PR c++/120776
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+extern int b[];
+
+void
+foo (int n)
+{
+ int a[n];
+ a[0] = 42;
+ auto [x] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ // { dg-error "cannot decompose variable length array 'int \\\[n\\\]'" "" { target *-*-* } .-1 }
+ auto [y] = b; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ // { dg-error "deduced type 'int \\\[\\\]' for '<structured bindings>' is incomplete" "" { target *-*-* } .-1 }
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++14 } }
+// { dg-options "" }
+
+template <typename T, typename U>
+constexpr bool is_same_v = false;
+
+template <typename T>
+constexpr bool is_same_v<T, T> = true;
+
+struct S { int a; long b; short c; };
+struct T { long long a; unsigned b; signed char c; };
+struct U { float a; double b; long double c; };
+struct V { S l, m, n; T o; U p; };
+constexpr S d = { 1, 2, 3 }, e = { 4, 5, 6 }, f = { 7, 8, 9 };
+constexpr T j = { 10, 11, 12 };
+U k = { 13.0f, 14.5, 15.5 }, m = { 7.0f, 7.0, 7.0 };
+V l = { d, e, f, j, k };
+struct A
+{
+ int x;
+ constexpr explicit A (int v) : x(v) {}
+ constexpr A &operator ++ () { ++x; return *this; }
+ constexpr int operator * () { return x; }
+ constexpr bool operator != (const A &o) { return x != o.x; }
+ constexpr A operator + (int o) { A r (x + o); return r; }
+};
+struct C
+{
+ int x, y, z;
+ constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
+ constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
+ constexpr C operator * () { return *this; }
+ constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
+ constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
+};
+
+namespace N
+{
+ struct B { constexpr B () {} };
+ constexpr A begin (B &) { return A (0); }
+ constexpr A end (B &) { return A (6); }
+}
+
+namespace O
+{
+ struct D { constexpr D () {} };
+ constexpr C begin (D &) { return C (0, 42, 5); }
+ constexpr C end (D &) { return C (6, 36, 11); }
+}
+
+long long
+foo ()
+{
+ long long r = 0;
+ template for (auto &g : { d, e, f, j, k }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += g.a + g.b + g.c;
+ decltype (g) s = g;
+ r += sizeof (s);
+ }
+ return r;
+}
+
+int
+bar ()
+{
+ int r = 0;
+ template for (auto i : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i;
+ static_assert (is_same_v <decltype (i), int>);
+ }
+ return r;
+}
+
+int
+baz ()
+{
+ int a[] = { 2, 4, 6, 8, 10 };
+ int r = 0, i = 0;
+ template for (const int &w : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (&w != &a[i++])
+ break;
+ r += w;
+ if (w == 6)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+long long
+qux ()
+{
+ long long r = 0;
+ template for (const auto &i : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i.a * i.b * i.c;
+ decltype (i.a) s = 0;
+ decltype (i.c) t = 0;
+ r += sizeof (s) + sizeof (t);
+ }
+ return r;
+}
+
+long long
+corge ()
+{
+ long long r = 0;
+ int z = 0;
+ template for (const auto &[g, h, i] : { d, e, f, j, m, k, k })// { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ ++z;
+ if (z == 5)
+ continue;
+ ++r;
+ if (z == 7)
+ break;
+ r += g + h + i;
+ decltype (h) s = 0;
+ r += sizeof (s) + sizeof (i);
+ }
+ return r;
+}
+
+int
+garply ()
+{
+ int r = 0;
+ template for (auto [g, h, i] : O::D {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += g + h + i; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+int
+freddy ()
+{
+ S a[] = { { 2, 4, 6 }, { 8, 10, 12 }, { 14, 16, 18 } };
+ int r = 0, i = 0;
+ template for (const auto &[u, v, w] : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (&u != &a[i].a || &v != &a[i].b || &w != &a[i].c)
+ break;
+ ++i;
+ r += u + v + w;
+ if (w == 12)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+long long
+quux ()
+{
+ long long r = 0;
+ template for (auto [i, j, k] : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i * j * k; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+long long
+boo ()
+{
+ long long r = 0;
+ template for (auto g : { 1, 2U, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ switch (g)
+ {
+ case 1:
+ r += 3;
+ break;
+ case 2:
+ r += 5;
+ break;
+ case 3:
+ r += 9;
+ break;
+ case 4:
+ r += 13;
+ break;
+ default:
+ __builtin_abort ();
+ }
+ }
+ return r;
+}
+
+int
+main ()
+{
+ if (foo () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U))
+ __builtin_abort ();
+ if (bar () != 15)
+ __builtin_abort ();
+ if (baz () != 34)
+ __builtin_abort ();
+ if (qux () != (4871 + 3 * (sizeof (int) + sizeof (short))
+ + sizeof (long long) + sizeof (signed char)
+ + sizeof (float) + sizeof (long double)))
+ __builtin_abort ();
+ if (corge () != (127 + 3 * (sizeof (long) + sizeof (short))
+ + sizeof (unsigned) + sizeof (signed char)
+ + sizeof (double) + sizeof (long double)))
+ __builtin_abort ();
+ if (garply () != 297)
+ __builtin_abort ();
+ if (freddy () != 92)
+ __builtin_abort ();
+ if (quux () != 4871)
+ __builtin_abort ();
+ if (boo () != 30)
+ __builtin_abort ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int a;
+long b;
+
+void
+foo ()
+{
+ template for (auto g : { &a, &b, 2L, &a }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message "required from here" "" { target *-*-* } .-1 }
+ decltype (*g) h = *g; // { dg-error "invalid type argument of unary" }
+ }
+}
+
+// { dg-message "In instantiation of 'template for' iteration 3:" "" { target *-*-* } 0 }
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S { using type = S; int s; };
+S a = { 1 }, b = { 2 };
+constexpr S c[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct T { using type = T; int s; };
+T d = { 8 };
+struct U {
+ constexpr const S *begin () const { return &c[0]; }
+ constexpr const S *end () const { return &c[s]; }
+ int s;
+};
+struct V { int a; long b; double c; };
+
+void
+foo ()
+{
+ template for (auto g : { a, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ template for (auto g : { d, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ static constexpr U u = { 3 };
+ template for (auto g : u) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g;
+ }
+ V v = { 9, 10L, 11.0 };
+ template for (auto g : v) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+}
+
+template <int N>
+void
+bar ()
+{
+ template for (auto g : { a, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ template for (auto g : { d, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ static constexpr U u = { 3 };
+ template for (auto g : u) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g;
+ }
+ V v = { 9, 10L, 11.0 };
+ template for (auto g : v) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+}
+
+template <typename S, typename U, typename V>
+void
+baz ()
+{
+ template for (auto g : { (S) a, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ template for (auto g : { d, (S) b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ static constexpr U u = { 3 };
+ template for (auto g : u) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ V v = { 9, 10L, 11.0 };
+ template for (auto g : v) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+}
+
+void
+qux ()
+{
+ bar <0> ();
+ baz <S, U, V> ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+constexpr int
+foo (auto const &... x) // { dg-warning "use of 'auto' in parameter declaration only available with" "" { target c++17_down } }
+{
+ int r = 0;
+ template for (auto const &c : {x...}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += c[0];
+ return r;
+}
+
+constexpr int c1[] = { 1, 2, 3 };
+constexpr int c2[] = { 4, 3, 2, 1 };
+static_assert (foo (c1, c2) == 5, "");
+
+template <typename T, unsigned long N>
+struct array
+{
+ T e[N];
+ constexpr T *begin () noexcept { return &e[0]; }
+ constexpr const T *begin () const noexcept { return &e[0]; }
+ constexpr T *end () noexcept { return &e[N]; }
+ constexpr const T *end () const noexcept { return &e[N]; }
+};
+
+static constexpr array <int, 3> a { 1, 2, 3 };
+
+constexpr int
+bar ()
+{
+ int r = 0;
+ template for (constexpr int s : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += sizeof (char[s]);
+ return r;
+}
+
+static_assert (bar () == 6, "");
+
+struct S { int i; short s; };
+
+constexpr long
+baz (S s)
+{
+ long r = 0;
+ template for (auto x : s) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += sizeof (x);
+ }
+ return r;
+}
+
+static_assert (baz (S {}) == sizeof (int) + sizeof (short), "");
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T> struct tuple_size;
+ template <int, typename> struct tuple_element;
+}
+
+struct S { int s; };
+constexpr S c[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct U {
+ constexpr const S *begin () const { return &c[0]; }
+ constexpr const S *end () const { return &c[s]; }
+ int s;
+};
+constexpr U u1 = { 3 }, u2 = { 0 };
+
+struct V {
+ int i, j;
+ template <int I> int &get () { return i; }
+};
+
+template<> struct std::tuple_size <V> { static const int value = 2; };
+template<int I> struct std::tuple_element <I, V> { using type = int; };
+
+struct W {
+ int w;
+ W (int x) : w (x) {}
+ ~W () {}
+};
+
+struct X {
+ V i, j;
+ template <int I> V &get () { return j; }
+};
+
+template<> struct std::tuple_size <X> { static const int value = 3; };
+template<int I> struct std::tuple_element <I, X> { using type = V; };
+
+long long
+foo ()
+{
+ long long r = 0;
+ template for (auto h = 2; constexpr auto g : u1) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += g.s + h;
+ template for (long long h = ++r; auto g : u2) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ __builtin_abort ();
+ return r;
+}
+
+long long
+bar ()
+{
+ long long r = 0;
+ template for (W w { 42 }; auto i : V { 42, 10 }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i + (w.w == 42);
+ return r;
+}
+
+long long
+baz ()
+{
+ long long r = 0;
+ template for (constexpr auto x = 5; auto [ i, j ] : X { { 5, 6 }, { 7, 8 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i + j + (x == 5); // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+V &&
+qux (V &&x) noexcept
+{
+ return static_cast<V &&> (x);
+}
+
+long long
+freddy ()
+{
+ long long r = 0;
+ V a { 1, 2 }, b { 3, 4 };
+ template for (auto i : { qux (static_cast<V &&> (a)), qux (static_cast<V &&> (b)) }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i.i + i.j;
+ return r;
+}
+
+int
+main ()
+{
+ if (foo () != 19)
+ __builtin_abort ();
+ if (bar () != 86)
+ __builtin_abort ();
+ if (baz () != 45)
+ __builtin_abort ();
+ if (freddy () != 10)
+ __builtin_abort ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+struct S { int s; };
+constexpr S c[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct U {
+ constexpr const S *begin () const { return &c[0]; }
+ constexpr const S *end () const { return &c[s]; }
+ int s;
+};
+constexpr U u1 = { 3 }, u2 = { 0 };
+struct V {
+ constexpr V () : a (1), b (2), c (3.0) {}
+ constexpr int foo () const { return a; }
+ constexpr unsigned long bar () const { return b; }
+ constexpr double baz () const { return c; }
+ int a;
+ unsigned long b;
+ double c;
+};
+
+long long
+foo ()
+{
+ long long r = 0;
+ template for (constexpr auto h = 2; constexpr auto g : u1) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ constexpr auto i = g.s + h;
+ r += i;
+ }
+ template for (constexpr auto h = 42; constexpr auto g : u2) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ constexpr auto i = g.s + h;
+ __builtin_abort ();
+ }
+ return r;
+}
+
+long long
+bar ()
+{
+ long long r = 0;
+ template for (constexpr S a { 42 }; constexpr auto b : { S { 1 }, S { 3 }, S { 5 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ constexpr auto c = a.s + b.s;
+ r += c;
+ }
+ return r;
+}
+
+constexpr V v;
+
+long long
+baz ()
+{
+ long long r = 0;
+ template for (constexpr auto x = 5; constexpr auto y : v) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ constexpr auto z = x + y;
+ r += z;
+ }
+ return r;
+}
+
+int
+main ()
+{
+ if (foo () != 18)
+ __builtin_abort ();
+ if (bar () != 135)
+ __builtin_abort ();
+ if (baz () != 21)
+ __builtin_abort ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T>
+ struct initializer_list {
+ private:
+ T *a;
+ decltype (sizeof 0) b;
+ public:
+ constexpr decltype (sizeof 0) size () const noexcept { return b; }
+ constexpr const T *begin () const noexcept { return a; }
+ constexpr const T *end () const noexcept { return begin () + size (); }
+};
+}
+
+struct A {};
+struct B { int b; B () : b (42) {} };
+struct C : public B { int c; C () : c (42), B () {} };
+extern int f[];
+
+void
+foo (int n)
+{
+ int c[0] = {}, d[n];
+ int e = 42;
+ d[0] = 42;
+ template for (auto a : A {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose class type 'A' without non-static data members" "" { target *-*-* } .-1 }
+ template for (int b : B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ;
+ template for (int i : c) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "empty structured binding" "" { target *-*-* } .-1 }
+ template for (int i : d) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose variable length array" "" { target *-*-* } .-1 }
+ template for (auto a : C {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose class type 'C': both it and its base class 'B' have non-static data members" "" { target *-*-* } .-1 }
+ template for (auto a : e) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose non-array non-class type 'int'" "" { target *-*-* } .-1 }
+ template for (auto a : { .id1 = 5, .id2 = 6LL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "designators in 'template for' initializer" "" { target *-*-* } .-1 }
+ template for (auto a : { .id3 { 5 }, .id4 = { 1.0 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "designators in 'template for' initializer" "" { target *-*-* } .-1 }
+ template for (int i : f) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose array of unknown bound 'int \\\[\\\]'" "" { target *-*-* } .-1 }
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A { int s; };
+constexpr A a[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct B {
+ constexpr const A *begin () const { return &a[0]; }
+ constexpr const A *end () const { return &a[s]; }
+ int s;
+};
+constexpr B b = { 3 };
+struct C {
+ C (int x) : s (x) {}
+ constexpr const A *begin () const { return &a[0]; }
+ constexpr const A *end () const { return &a[s]; }
+ int s;
+};
+struct D {
+ constexpr D (int x) : s (x) {}
+ constexpr const A *begin () const { return &a[0]; }
+ const A *end () const { return &a[s]; }
+ int s;
+};
+struct E {
+ constexpr E (int x) : s (x) {}
+ const A *begin () const { return &a[0]; }
+ constexpr const A *end () const { return &a[s]; }
+ int s;
+};
+struct F { F () : s (42) {} F (int x) : s (x) {} int s; };
+F g[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct G {
+ constexpr G (int x) : s (x) {}
+ constexpr F *begin () const { return &g[0]; }
+ constexpr F *end () const { return &g[s]; }
+ int s;
+};
+struct H { int a; F b; int c; };
+
+void
+foo ()
+{
+ B c = { 3 };
+ template for (constexpr auto g : c) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'c' is not a constant expression" "" { target *-*-* } .-1 }
+ C d = { 3 };
+ template for (constexpr auto g : d) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'d' is not a constant expression" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function 'const A\\\* C::begin\\\(\\\) const'" "" { target c++11_down } .-1 }
+ // { dg-error "call to non-'constexpr' function 'const A\\\* C::end\\\(\\\) const'" "" { target c++11_down } .-2 }
+ constexpr D e = { 3 };
+ template for (constexpr auto g : e) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'e' is not a constant expression" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function 'const A\\\* D::end\\\(\\\) const'" "" { target *-*-* } .-1 }
+ constexpr E f = { 3 };
+ template for (constexpr auto g : f) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'f' is not a constant expression" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function 'const A\\\* E::begin\\\(\\\) const'" "" { target *-*-* } .-1 }
+ constexpr G h = { 3 };
+ template for (constexpr auto g : h) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'h' is not a constant expression" "" { target *-*-* } .-1 }
+ template for (constexpr auto g : { 1, 2, F { 3 }, 4L }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "the type 'const F' of 'constexpr' variable 'g' is not literal" "" { target *-*-* } .-1 }
+ template for (constexpr auto g : H {})// { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "the type 'const F' of 'constexpr' variable 'g' is not literal" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function 'F::F\\\(\\\)'" "" { target *-*-* } .-2 }
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+// { dg-additional-options "-frange-for-ext-temps" { target c++20_down } }
+
+int c;
+struct A {
+ A () { ++c; }
+ ~A () { --c; }
+ A (int x) : a (x) { ++c; }
+ A (const A &x) : a (x.a) { ++c; }
+ int a;
+};
+struct B { int a; long b; double c; short d; };
+
+B &
+foo (A x, A y, A z)
+{
+ static B r = { 1, 2, 42, 3 };
+ return r;
+}
+
+int
+main ()
+{
+ int r = 0;
+ if (c != 0)
+ __builtin_abort ();
+ template for (auto a : foo (A { 1 }, A { 2 }, A { 42 })) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (c != 3)
+ __builtin_abort ();
+ r += a;
+ }
+ if (c != 0 || r != 48)
+ __builtin_abort ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+struct S { int a; long b; short c; };
+struct A
+{
+ int x;
+ constexpr explicit A (int v) : x(v) {}
+ constexpr A &operator ++ () { ++x; return *this; }
+ constexpr int operator * () { return x; }
+ constexpr bool operator != (const A &o) { return x != o.x; }
+ constexpr A operator + (int o) { A r (x + o); return r; }
+};
+
+namespace N
+{
+ struct B { constexpr B () {} };
+ constexpr A begin (B &) { return A (0); }
+ constexpr A end (B &) { return A (6); }
+}
+
+void
+foo ()
+{
+ template for (int a = 1; auto a : { 1, 2L }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "conflicting declaration 'auto a'" "" { target *-*-* } .-1 }
+ template for (int b = 1; auto c : { 1, 2L }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ;
+ int b = 1;
+ int c = 2;
+ template for (int d = 1; auto d : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "conflicting declaration 'auto d'" "" { target *-*-* } .-1 }
+ template for (int e = 1; auto e : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "conflicting declaration 'auto e'" "" { target *-*-* } .-1 }
+ template for (int f = 1; auto f : S { 1, 2, 3}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "conflicting declaration 'auto f'" "" { target *-*-* } .-1 }
+ template for (auto g : { 1, 2LL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ int g = 5; // { dg-error "conflicting declaration 'int g'" }
+ // { dg-error "redeclaration of 'int g'" "" { target *-*-* } .-1 }
+ template for (auto h : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ int h = 6; // { dg-error "redeclaration of 'int h'" }
+ template for (auto i : S { 1, 2, 3}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ int i = 7; // { dg-error "conflicting declaration 'int i'" }
+ // { dg-error "redeclaration of 'int i'" "" { target *-*-* } .-1 }
+ template for (auto j : { 1, 2LL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ int j = 5; // { dg-error "conflicting declaration 'int j'" }
+ } // { dg-error "redeclaration of 'int j'" "" { target *-*-* } .-1 }
+ template for (auto k : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ int k = 6; // { dg-error "redeclaration of 'int k'" }
+ }
+ template for (auto l : S { 1, 2, 3}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ int l = 7; // { dg-error "conflicting declaration 'int l'" }
+ } // { dg-error "redeclaration of 'int l'" "" { target *-*-* } .-1 }
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T> struct tuple_size;
+ template <int, typename> struct tuple_element;
+}
+
+struct V {
+ int i, j;
+ template <int I> int &get () { return i; }
+};
+
+template<> struct std::tuple_size <V> { static const int value = 5; };
+template<int I> struct std::tuple_element <I, V> { using type = int; };
+
+constexpr V c[] = { { 3, 4 }, { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 } };
+struct U {
+ constexpr const V *begin () const { return &c[0]; }
+ constexpr const V *end () const { return &c[s]; }
+ int s;
+};
+constexpr U u1 = { 3 }, u2 = { 0 };
+
+struct W {
+ int w;
+ W (int x) : w (x) {}
+ ~W () {}
+};
+
+struct X {
+ V i, j;
+ template <int I> V &get () { return j; }
+};
+
+template<> struct std::tuple_size <X> { static const int value = 3; };
+template<int I> struct std::tuple_element <I, X> { using type = V; };
+
+template <int N>
+long long
+foo ()
+{
+ long long r = 0;
+ template for (auto h = 2; auto [_, ...i, _] : u1) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (sizeof... (i) != 3) // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 }
+ __builtin_abort (); // { dg-warning "name-independent declarations only available with" "" { target c++23_down } .-3 }
+ r += i...[1] + h; // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+ }
+ template for (long long h = ++r; auto [...i, j] : u2) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ __builtin_abort (); // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 }
+ return r;
+}
+
+template <int N>
+long long
+bar ()
+{
+ long long r = 0;
+ template for (W w { 42 }; auto [...i, j] : { V { 42, 10 }, V { 15, 26 }, V { 93, 12 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (sizeof... (i) != 4) // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 }
+ __builtin_abort ();
+ r += i...[3] + (w.w == 42); // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+ }
+ return r;
+}
+
+template <int N>
+long long
+baz ()
+{
+ long long r = 0;
+ template for (constexpr auto x = 5; auto [ ...j ] : X { { 5, 6 }, { 7, 8 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (sizeof... (j) != 5) // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 }
+ __builtin_abort ();
+ r += j...[4] + j...[0] + (x == 5); // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+ }
+ return r;
+}
+
+int
+main ()
+{
+ if (foo <0> () != 19)
+ __builtin_abort ();
+ if (bar <1> () != 153)
+ __builtin_abort ();
+ if (baz <2> () != 45)
+ __builtin_abort ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++17 } }
+// { dg-options "" }
+
+template <typename T, typename U>
+constexpr bool is_same_v = false;
+
+template <typename T>
+constexpr bool is_same_v<T, T> = true;
+
+struct S { int a; long b; short c; };
+struct T { long long a; unsigned b; signed char c; };
+struct U { float a; double b; long double c; };
+struct V { S l, m, n; T o; U p; };
+constexpr S d = { 1, 2, 3 }, e = { 4, 5, 6 }, f = { 7, 8, 9 };
+constexpr T j = { 10, 11, 12 };
+U k = { 13.0f, 14.5, 15.5 }, m = { 7.0f, 7.0, 7.0 };
+V l = { d, e, f, j, k };
+struct A
+{
+ int x;
+ constexpr explicit A (int v) : x(v) {}
+ constexpr A &operator ++ () { ++x; return *this; }
+ constexpr int operator * () { return x; }
+ constexpr bool operator != (const A &o) { return x != o.x; }
+ constexpr A operator + (int o) { A r (x + o); return r; }
+};
+struct C
+{
+ int x, y, z;
+ constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
+ constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
+ constexpr C operator * () { return *this; }
+ constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
+ constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
+};
+
+namespace N
+{
+ struct B { constexpr B () {} };
+ constexpr A begin (B &) { return A (0); }
+ constexpr A end (B &) { return A (6); }
+}
+
+namespace O
+{
+ struct D { constexpr D () {} };
+ constexpr C begin (D &) { return C (0, 42, 5); }
+ constexpr C end (D &) { return C (6, 36, 11); }
+}
+
+#if __cpp_nontype_template_parameter_class >= 201806L
+template <auto ... Z>
+long long
+foo ()
+{
+ long long r = 0;
+ template for (const auto &g : { Z... }) // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } }
+ {
+ r += g.a + g.b + g.c;
+ decltype (g) s = g;
+ r += sizeof (s);
+ }
+ return r;
+}
+#endif
+
+template <typename T, int N>
+int
+bar ()
+{
+ int r = 0;
+ template for (auto i : T {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i + N;
+ static_assert (is_same_v <decltype (i), int>);
+ }
+ return r;
+}
+
+template <typename T>
+int
+baz ()
+{
+ T a[] = { 2, 4, 6, 8, 10 };
+ int r = 0, i = 0;
+ template for (const int &w : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (&w != &a[i++])
+ break;
+ r += w;
+ if (w == 6)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+template <typename T>
+long long
+qux ()
+{
+ T l = { d, e, f, j, k };
+ long long r = 0;
+ template for (const auto &i : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i.a * i.b * i.c;
+ decltype (i.a) s = 0;
+ decltype (i.c) t = 0;
+ r += sizeof (s) + sizeof (t);
+ }
+ return r;
+}
+
+template <typename T>
+long long
+corge ()
+{
+ long long r = 0;
+ int z = 0;
+ template for (const auto &[g, h, i] : { d, e, f, j, (T) m, k, k })// { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ ++z;
+ if (z == 5)
+ continue;
+ ++r;
+ if (z == 7)
+ break;
+ r += g + h + i;
+ decltype (h) s = 0;
+ r += sizeof (s) + sizeof (i);
+ }
+ return r;
+}
+
+template <typename T>
+int
+garply ()
+{
+ int r = 0;
+ template for (auto [g, h, i] : T {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += g + h + i;
+ return r;
+}
+
+template <typename T>
+int
+freddy ()
+{
+ T a[] = { { 2, 4, 6 }, { 8, 10, 12 }, { 14, 16, 18 } };
+ int r = 0, i = 0;
+ template for (const auto &[u, v, w] : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (&u != &a[i].a || &v != &a[i].b || &w != &a[i].c)
+ break;
+ ++i;
+ r += u + v + w;
+ if (w == 12)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+template <typename T, typename U, int N>
+long long
+quux ()
+{
+ T l = { d, e, f, j, k };
+ long long r = 0;
+ template for (auto [i, j, k] : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ U u = -1;
+ r += i * j * k + u + N;
+ }
+ return r;
+}
+
+int
+main ()
+{
+#if __cpp_nontype_template_parameter_class >= 201806L
+ if (foo <d, e, f, j, U { 13.0f, 14.5, 15.5 }> () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U))
+ __builtin_abort ();
+#endif
+ if (bar <N::B, 0> () != 15)
+ __builtin_abort ();
+ if (bar <N::B, 1> () != 21)
+ __builtin_abort ();
+ if (baz <int> () != 34)
+ __builtin_abort ();
+ if (qux <V> () != (4871 + 3 * (sizeof (int) + sizeof (short))
+ + sizeof (long long) + sizeof (signed char)
+ + sizeof (float) + sizeof (long double)))
+ __builtin_abort ();
+ if (corge <U> () != (127 + 3 * (sizeof (long) + sizeof (short))
+ + sizeof (unsigned) + sizeof (signed char)
+ + sizeof (double) + sizeof (long double)))
+ __builtin_abort ();
+ if (garply <O::D> () != 297)
+ __builtin_abort ();
+ if (freddy <S> () != 92)
+ __builtin_abort ();
+ if (quux <V, unsigned char, 1> () != 4876L + 5L * (unsigned char) -1)
+ __builtin_abort ();
+ if (quux <V, int, 3> () != 4881)
+ __builtin_abort ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++14 } }
+// { dg-options "" }
+
+template <typename T, typename U>
+constexpr bool is_same_v = false;
+
+template <typename T>
+constexpr bool is_same_v<T, T> = true;
+
+struct S { int a; long b; short c; };
+struct T { long long a; unsigned b; signed char c; };
+struct U { float a; double b; long double c; };
+struct V { S l, m, n; T o; U p; };
+constexpr S d = { 1, 2, 3 }, e = { 4, 5, 6 }, f = { 7, 8, 9 };
+constexpr T j = { 10, 11, 12 };
+U k = { 13.0f, 14.5, 15.5 }, m = { 7.0f, 7.0, 7.0 };
+V l = { d, e, f, j, k };
+struct A
+{
+ int x;
+ constexpr explicit A (int v) : x(v) {}
+ constexpr A &operator ++ () { ++x; return *this; }
+ constexpr int operator * () { return x; }
+ constexpr bool operator != (const A &o) { return x != o.x; }
+ constexpr A operator + (int o) { A r (x + o); return r; }
+};
+struct C
+{
+ int x, y, z;
+ constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
+ constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
+ constexpr C operator * () { return *this; }
+ constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
+ constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
+};
+
+namespace N
+{
+ struct B { constexpr B () {} };
+ constexpr A begin (B &) { return A (0); }
+ constexpr A end (B &) { return A (6); }
+}
+
+namespace O
+{
+ struct D { constexpr D () {} };
+ constexpr C begin (D &) { return C (0, 42, 5); }
+ constexpr C end (D &) { return C (6, 36, 11); }
+}
+
+template <int N>
+long long
+foo ()
+{
+ long long r = 0;
+ template for (auto &g : { d, e, f, j, k }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += g.a + g.b + g.c;
+ decltype (g) s = g;
+ r += sizeof (s) + N;
+ }
+ return r;
+}
+
+template <typename T>
+int
+bar ()
+{
+ int r = 0;
+ template for (auto i : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i;
+ static_assert (is_same_v <decltype (i), T>);
+ }
+ return r;
+}
+
+template <int N>
+int
+baz ()
+{
+ int a[] = { 2, 4, N, 8, 10 };
+ int r = 0, i = 0;
+ template for (const int &w : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (&w != &a[i++])
+ break;
+ r += w;
+ if (w == N)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+template <int N>
+long long
+qux ()
+{
+ long long r = 0;
+ template for (const auto &i : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i.a * i.b * i.c;
+ decltype (i.a) s = N;
+ decltype (i.c) t = 0;
+ r += sizeof (s) + sizeof (t);
+ }
+ return r;
+}
+
+template <long long N>
+long long
+corge ()
+{
+ long long r = N;
+ int z = 0;
+ template for (const auto &[g, h, i] : { d, e, f, j, m, k, k })// { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ ++z;
+ if (z == 5)
+ continue;
+ ++r;
+ if (z == 7)
+ break;
+ r += g + h + i;
+ decltype (h) s = 0;
+ r += sizeof (s) + sizeof (i);
+ }
+ return r;
+}
+
+template <typename T>
+int
+garply ()
+{
+ int r = 0;
+ template for (auto [g, h, i] : O::D {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += g + h + i + (T) 0; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+template <int N>
+int
+freddy ()
+{
+ S a[] = { { 2, 4, 6 }, { 8, N, 12 }, { 14, 16, 18 } };
+ int r = 0, i = 0;
+ template for (const auto &[u, v, w] : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (&u != &a[i].a || &v != &a[i].b || &w != &a[i].c)
+ break;
+ ++i;
+ r += u + v + w;
+ if (w == 12)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+template <long long N>
+long long
+quux ()
+{
+ long long r = N;
+ template for (auto [i, j, k] : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i * j * k; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+int
+main ()
+{
+ if (foo <0> () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U))
+ __builtin_abort ();
+ if (foo <42> () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U) + 5 * 42)
+ __builtin_abort ();
+ if (bar <int> () != 15)
+ __builtin_abort ();
+ if (baz <6> () != 34)
+ __builtin_abort ();
+ if (qux <0> () != (4871 + 3 * (sizeof (int) + sizeof (short))
+ + sizeof (long long) + sizeof (signed char)
+ + sizeof (float) + sizeof (long double)))
+ __builtin_abort ();
+ if (corge <0> () != (127 + 3 * (sizeof (long) + sizeof (short))
+ + sizeof (unsigned) + sizeof (signed char)
+ + sizeof (double) + sizeof (long double)))
+ __builtin_abort ();
+ if (garply <long long> () != 297)
+ __builtin_abort ();
+ if (freddy <10> () != 92)
+ __builtin_abort ();
+ if (quux <0> () != 4871)
+ __builtin_abort ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++14 } }
+// { dg-options "" }
+
+struct S { int a; long b; short c; };
+struct T { long long a; unsigned b; signed char c; };
+struct U { float a; double b; long double c; };
+constexpr S d = { 1, 2, 3 }, f = { 7, 8, 9 };
+constexpr T j = { 10, 11, 12 };
+constexpr U k = { 13.0f, 14.5, 15.5 };
+
+template <typename T>
+long long
+foo ()
+{
+ auto s = [] (auto f)
+ {
+ long long r = 0;
+ template for (auto g : { d, T { 4, 5, 6 }, f, j, k }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += g.a + g.b + g.c;
+ decltype (g) s = g;
+ r += sizeof (s);
+ }
+ return r;
+ };
+ return s (f);
+}
+
+int
+main ()
+{
+ if (foo <S> () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U))
+ __builtin_abort ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+void
+foo (int x)
+{
+ switch (x)
+ {
+ case 1:
+ template for (auto g : { 1, 2U, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ case 2: // { dg-error "jump to case label" }
+ break;
+ }
+ case 3:
+ template for (auto g : { 1, 2U, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ default: // { dg-error "jump to case label" }
+ break;
+ }
+ }
+ template for (auto g : { 1, 2U, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ lab1:; // { dg-error "identifier label 'lab1' in 'template for' body" }
+ }
+ switch (x)
+ {
+ case 1:
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ case 2: // { dg-error "jump to case label" }
+ break;
+ }
+ case 3:
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ default: // { dg-error "jump to case label" }
+ break;
+ }
+ }
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ lab2:; // { dg-error "identifier label 'lab2' in 'template for' body" }
+ }
+}
+
+template <typename T, T N>
+void
+bar (int x)
+{
+ switch (x)
+ {
+ case 1:
+ template for (auto g : { 1, N, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ case 2: // { dg-error "jump to case label" }
+ break;
+ }
+ case 3:
+ template for (auto g : { 1, N, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ default: // { dg-error "jump to case label" }
+ break;
+ }
+ }
+ template for (auto g : { 1, 2U, N, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ lab1:; // { dg-error "identifier label 'lab1' in 'template for' body" }
+ }
+ switch (x)
+ {
+ case 1:
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ case 2: // { dg-error "jump to case label" }
+ break;
+ }
+ case 3:
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ default: // { dg-error "jump to case label" }
+ break;
+ }
+ }
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ lab2:; // { dg-error "identifier label 'lab2' in 'template for' body" }
+ }
+}
+
+void
+baz (int x)
+{
+ bar <unsigned, 2U> (x);
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+
+int z[3];
+
+void
+foo ()
+{
+ template for (static auto a : {}) // { dg-error "for-range-declaration cannot be 'static'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (thread_local auto a : {}) // { dg-error "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (__thread auto a : {}) // { dg-error "for-range-declaration cannot be '__thread'" }
+ ; // { dg-error "function-scope 'a' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (register auto a : {}) // { dg-error "for-range-declaration cannot be 'register'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (extern auto a : {}) // { dg-error "for-range-declaration cannot be 'extern'" }
+ ; // { dg-error "'a' has both 'extern' and initializer" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto a : {}) // { dg-error "non-member 'a' cannot be declared 'mutable'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (virtual auto a : {}) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (explicit auto a : {}) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (friend auto a : {}) // { dg-error "'friend' used outside of class" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (typedef auto a : {}) // { dg-error "typedef declared 'auto'" }
+ ; // { dg-error "typedef 'a' is initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto a : {}) // { dg-error "a variable cannot be declared 'consteval'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto a : {}) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto a : {}) // { dg-error "'inline' specifier invalid for variable 'a' declared at block scope" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (struct S { int a; } a : {}) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (enum E { E0 } a : {}) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+}
+
+void
+bar ()
+{
+ template for (static auto a : z) // { dg-error "for-range-declaration cannot be 'static'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (thread_local auto a : z) // { dg-error "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (__thread auto a : z) // { dg-error "for-range-declaration cannot be '__thread'" }
+ ; // { dg-error "function-scope 'a' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (register auto a : z) // { dg-error "for-range-declaration cannot be 'register'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (extern auto a : z) // { dg-error "for-range-declaration cannot be 'extern'" }
+ ; // { dg-error "'a' has both 'extern' and initializer" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto a : z) // { dg-error "non-member 'a' cannot be declared 'mutable'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (virtual auto a : z) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (explicit auto a : z) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (friend auto a : z) // { dg-error "'friend' used outside of class" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (typedef auto a : z) // { dg-error "typedef declared 'auto'" }
+ ; // { dg-error "typedef 'a' is initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto a : z) // { dg-error "a variable cannot be declared 'consteval'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto a : z) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto a : z) // { dg-error "'inline' specifier invalid for variable 'a' declared at block scope" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (struct S { int a; } a : z) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "conversion from 'int' to non-scalar type 'bar\\\(\\\)::S' requested" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ // { dg-error "conversion from 'int' to non-scalar type 'bar\\\(\\\)::S' requested" "" { target *-*-* } .-2 }
+ template for (enum E { E0 } a : z) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "invalid conversion from 'int' to 'bar\\\(\\\)::E'" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ // { dg-error "invalid conversion from 'int' to 'bar\\\(\\\)::E'" "" { target *-*-* } .-2 }
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int z[3];
+
+void
+foo ()
+{
+ template for (static auto a : {}) // { dg-warning "for-range-declaration cannot be 'static'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (thread_local auto a : {}) // { dg-warning "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (__thread auto a : {}) // { dg-warning "for-range-declaration cannot be '__thread'" }
+ ; // { dg-warning "function-scope 'a' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (register auto a : {}) // { dg-warning "for-range-declaration cannot be 'register'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (extern auto a : {}) // { dg-warning "for-range-declaration cannot be 'extern'" }
+ ; // { dg-error "'a' has both 'extern' and initializer" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto a : {}) // { dg-error "non-member 'a' cannot be declared 'mutable'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (virtual auto a : {}) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (explicit auto a : {}) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (friend auto a : {}) // { dg-error "'friend' used outside of class" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (typedef auto a : {}) // { dg-error "typedef declared 'auto'" }
+ ; // { dg-error "typedef 'a' is initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto a : {}) // { dg-error "a variable cannot be declared 'consteval'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto a : {}) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto a : {}) // { dg-error "'inline' specifier invalid for variable 'a' declared at block scope" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (struct S { int a; } a : {}) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (enum E { E0 } a : {}) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+}
+
+void
+bar ()
+{
+ template for (static auto a : z) // { dg-warning "for-range-declaration cannot be 'static'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (thread_local auto a : z) // { dg-warning "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (__thread auto a : z) // { dg-warning "for-range-declaration cannot be '__thread'" }
+ ; // { dg-warning "function-scope 'a' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (register auto a : z) // { dg-warning "for-range-declaration cannot be 'register'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (extern auto a : z) // { dg-warning "for-range-declaration cannot be 'extern'" }
+ ; // { dg-error "'a' has both 'extern' and initializer" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto a : z) // { dg-error "non-member 'a' cannot be declared 'mutable'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (virtual auto a : z) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (explicit auto a : z) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (friend auto a : z) // { dg-error "'friend' used outside of class" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (typedef auto a : z) // { dg-error "typedef declared 'auto'" }
+ ; // { dg-error "typedef 'a' is initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto a : z) // { dg-error "a variable cannot be declared 'consteval'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto a : z) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto a : z) // { dg-error "'inline' specifier invalid for variable 'a' declared at block scope" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (struct S { int a; } a : z) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "conversion from 'int' to non-scalar type 'bar\\\(\\\)::S' requested" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ // { dg-error "conversion from 'int' to non-scalar type 'bar\\\(\\\)::S' requested" "" { target *-*-* } .-2 }
+ template for (enum E { E0 } a : z) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "invalid conversion from 'int' to 'bar\\\(\\\)::E'" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ // { dg-error "invalid conversion from 'int' to 'bar\\\(\\\)::E'" "" { target *-*-* } .-2 }
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+
+struct S { int y; } z[3];
+
+template <int N>
+void
+foo ()
+{
+ template for (static auto [ a ] : {}) // { dg-error "for-range-declaration cannot be 'static'" }
+ ; // { dg-error "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (thread_local auto [ a ] : {}) // { dg-error "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-error "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (__thread auto [ a ] : {}) // { dg-error "for-range-declaration cannot be '__thread'" }
+ ; // { dg-error "function-scope 'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-error "structured binding declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-3 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-4 }
+ template for (register auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'register'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (extern auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'extern'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'mutable'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (virtual auto [ a ] : {}) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (explicit auto [ a ] : {}) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (friend auto [ a ] : {}) // { dg-error "'friend' used outside of class" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (typedef auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'typedef'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'consteval'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto [ a ] : {}) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'inline'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+}
+
+template <int N>
+void
+bar ()
+{
+ template for (static auto [ a ] : z) // { dg-error "for-range-declaration cannot be 'static'" }
+ ; // { dg-error "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (thread_local auto [ a ] : z) // { dg-error "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-error "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (__thread auto [ a ] : z) // { dg-error "for-range-declaration cannot be '__thread'" }
+ ; // { dg-error "function-scope 'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-error "structured binding declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-3 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-4 }
+ template for (register auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'register'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (extern auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'extern'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'mutable'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (virtual auto [ a ] : z) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (explicit auto [ a ] : z) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (friend auto [ a ] : z) // { dg-error "'friend' used outside of class" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (typedef auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'typedef'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'consteval'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto [ a ] : z) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'inline'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+}
+
+void
+baz ()
+{
+ foo <0> ();
+ bar <0> ();
+}
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S { int y; } z[3];
+
+template <int N>
+void
+foo ()
+{
+ template for (static auto [ a ] : {}) // { dg-warning "for-range-declaration cannot be 'static'" }
+ ; // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (thread_local auto [ a ] : {}) // { dg-warning "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-warning "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (__thread auto [ a ] : {}) // { dg-warning "for-range-declaration cannot be '__thread'" }
+ ; // { dg-warning "function-scope 'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-warning "structured binding declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-3 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-4 }
+ template for (register auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'register'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (extern auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'extern'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'mutable'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (virtual auto [ a ] : {}) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (explicit auto [ a ] : {}) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (friend auto [ a ] : {}) // { dg-error "'friend' used outside of class" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (typedef auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'typedef'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'consteval'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto [ a ] : {}) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'inline'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+}
+
+template <int N>
+void
+bar ()
+{
+ template for (static auto [ a ] : z) // { dg-warning "for-range-declaration cannot be 'static'" }
+ ; // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (thread_local auto [ a ] : z) // { dg-warning "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-warning "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (__thread auto [ a ] : z) // { dg-warning "for-range-declaration cannot be '__thread'" }
+ ; // { dg-warning "function-scope 'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-warning "structured binding declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-3 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-4 }
+ template for (register auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'register'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (extern auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'extern'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'mutable'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (virtual auto [ a ] : z) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (explicit auto [ a ] : z) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (friend auto [ a ] : z) // { dg-error "'friend' used outside of class" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (typedef auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'typedef'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'consteval'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto [ a ] : z) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'inline'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+}
+
+void
+baz ()
+{
+ foo <0> ();
+ bar <0> ();
+}
#elif __cpp_trivial_relocatability != 202502
# error "__cpp_trivial_relocatability != 202502"
#endif
+
+#ifndef __cpp_expansion_statements
+# error "__cpp_expansion_statements"
+#elif __cpp_expansion_statements != 202506
+# error "__cpp_expansion_statements != 202506"
+#endif