Ping. On Wed, Nov 06, 2024 at 03:33:00PM -0500, Marek Polacek wrote: > On Mon, Nov 04, 2024 at 11:10:05PM -0500, Jason Merrill wrote: > > On 10/30/24 4:59 PM, Marek Polacek wrote: > > > On Wed, Oct 30, 2024 at 09:01:36AM -0400, Patrick Palka wrote: > > > > On Tue, 29 Oct 2024, Marek Polacek wrote: > > > --- a/gcc/cp/cp-tree.h > > > +++ b/gcc/cp/cp-tree.h > > > @@ -451,6 +451,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; > > > ATOMIC_CONSTR_MAP_INSTANTIATED_P (in ATOMIC_CONSTR) > > > contract_semantic (in ASSERTION_, PRECONDITION_, > > > POSTCONDITION_STMT) > > > RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR) > > > + PACK_INDEX_PARENTHESIZED_P (in PACK_INDEX_*) > > > 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE) > > > TI_PENDING_TEMPLATE_FLAG. > > > TEMPLATE_PARMS_FOR_INLINE. > > > @@ -2258,7 +2259,8 @@ enum languages { lang_c, lang_cplusplus }; > > > || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \ > > > || TREE_CODE (T) == DECLTYPE_TYPE \ > > > || TREE_CODE (T) == TRAIT_TYPE \ > > > - || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE) > > > + || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE \ > > > + || PACK_INDEX_P (T)) > > > > Just PACK_INDEX_TYPE here, I think? > > I think so too. Done. > > > > /* Nonzero if T is a class (or struct or union) type. Also nonzero > > > for template type parameters, typename types, and instantiated > > > @@ -4001,6 +4003,9 @@ struct GTY(()) lang_decl { > > > #define PACK_EXPANSION_CHECK(NODE) \ > > > TREE_CHECK2 (NODE, TYPE_PACK_EXPANSION, EXPR_PACK_EXPANSION) > > > +#define PACK_INDEX_CHECK(NODE) \ > > > + TREE_CHECK2 (NODE, PACK_INDEX_TYPE, PACK_INDEX_EXPR) > > > + > > > /* Extracts the type or expression pattern from a TYPE_PACK_EXPANSION or > > > EXPR_PACK_EXPANSION. */ > > > #define PACK_EXPANSION_PATTERN(NODE) \ > > > @@ -4025,6 +4030,22 @@ struct GTY(()) lang_decl { > > > ? &TYPE_MAX_VALUE_RAW (NODE) \ > > > : &TREE_OPERAND ((NODE), 2)) > > > +/* True if NODE is a pack index. */ > > > +#define PACK_INDEX_P(NODE) \ > > > + (TREE_CODE (NODE) == PACK_INDEX_TYPE \ > > > + || TREE_CODE (NODE) == PACK_INDEX_EXPR) > > > + > > > +/* For a pack index T...[N], the pack expansion T. */ > > > > "the pack expansion T..."? > > Done. > > > > +#define PACK_INDEX_PACK(NODE) \ > > > + (TREE_CODE (PACK_INDEX_CHECK (NODE)) == PACK_INDEX_TYPE \ > > > + ? TREE_TYPE (NODE) : TREE_OPERAND (NODE, 0)) > > > + > > > +/* For a pack index T...[N], the index N. */ > > > +#define PACK_INDEX_INDEX(NODE) \ > > > + *(TREE_CODE (PACK_INDEX_CHECK (NODE)) == PACK_INDEX_TYPE \ > > > + ? &TYPE_MAX_VALUE_RAW (NODE) \ > > > + : &TREE_OPERAND ((NODE), 1)) > > > + > > > /* True iff this pack expansion is within a function context. */ > > > #define PACK_EXPANSION_LOCAL_P(NODE) \ > > > TREE_LANG_FLAG_0 (PACK_EXPANSION_CHECK (NODE)) > > > @@ -4042,6 +4063,11 @@ struct GTY(()) lang_decl { > > > #define PACK_EXPANSION_FORCE_EXTRA_ARGS_P(NODE) \ > > > TREE_LANG_FLAG_3 (PACK_EXPANSION_CHECK (NODE)) > > > +/* Indicates whether a pack expansion has been parenthesized. Used for > > > + a pack expansion in a decltype. */ > > > +#define PACK_INDEX_PARENTHESIZED_P(NODE) \ > > > + TREE_LANG_FLAG_1 (PACK_INDEX_CHECK (NODE)) > > > > This should only apply to PACK_INDEX_EXPR, I think? > > True, fixed. > > > > /* True iff the wildcard can match a template parameter pack. */ > > > #define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE) > > > @@ -7581,6 +7607,7 @@ extern bool template_parameter_pack_p > > > (const_tree); > > > extern bool function_parameter_pack_p (const_tree); > > > extern bool function_parameter_expanded_from_pack_p (tree, tree); > > > extern tree make_pack_expansion (tree, tsubst_flags_t = > > > tf_warning_or_error); > > > +extern tree make_pack_index (tree, tree); > > > extern bool check_for_bare_parameter_packs (tree, location_t = > > > UNKNOWN_LOCATION); > > > extern tree build_template_info (tree, tree); > > > extern tree get_template_info (const_tree); > > > @@ -7906,6 +7933,8 @@ extern tree finish_underlying_type (tree); > > > extern tree calculate_bases (tree, tsubst_flags_t); > > > extern tree finish_bases (tree, bool); > > > extern tree calculate_direct_bases (tree, tsubst_flags_t); > > > +extern tree pack_index_element (tree, tree, bool, > > > + tsubst_flags_t); > > > extern tree finish_offsetof (tree, tree, > > > location_t); > > > extern void finish_decl_cleanup (tree, tree); > > > extern void finish_eh_cleanup (tree); > > > diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc > > > index f4203123737..15d41b55557 100644 > > > --- a/gcc/cp/cxx-pretty-print.cc > > > +++ b/gcc/cp/cxx-pretty-print.cc > > > @@ -1220,6 +1220,13 @@ cxx_pretty_printer::expression (tree t) > > > pp_cxx_ws_string (this, "..."); > > > break; > > > + case PACK_INDEX_EXPR: > > > + expression (PACK_INDEX_PACK (t)); > > > + pp_cxx_left_bracket (this); > > > + expression (PACK_INDEX_INDEX (t)); > > > + pp_cxx_right_bracket (this); > > > + break; > > > + > > > case UNARY_LEFT_FOLD_EXPR: > > > pp_cxx_unary_left_fold_expression (this, t); > > > break; > > > @@ -1920,6 +1927,13 @@ cxx_pretty_printer::type_id (tree t) > > > pp_cxx_ws_string (this, "..."); > > > break; > > > + case PACK_INDEX_TYPE: > > > + type_id (PACK_INDEX_PACK (t)); > > > + pp_cxx_left_bracket (this); > > > + expression (PACK_INDEX_INDEX (t)); > > > + pp_cxx_right_bracket (this); > > > + break; > > > + > > > case TYPE_ARGUMENT_PACK: > > > { > > > tree args = ARGUMENT_PACK_ARGS (t); > > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc > > > index 7ef79b90868..c62c9d7312e 100644 > > > --- a/gcc/cp/error.cc > > > +++ b/gcc/cp/error.cc > > > @@ -814,6 +814,13 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) > > > pp_cxx_ws_string (pp, "..."); > > > break; > > > + case PACK_INDEX_TYPE: > > > + dump_type (pp, PACK_INDEX_PACK (t), flags); > > > + pp_cxx_left_bracket (pp); > > > + dump_expr (pp, PACK_INDEX_INDEX (t), flags & ~TFF_EXPR_IN_PARENS); > > > + pp_cxx_right_bracket (pp); > > > + break; > > > + > > > case TYPE_ARGUMENT_PACK: > > > dump_template_argument (pp, t, flags); > > > break; > > > @@ -1088,6 +1095,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, > > > int flags) > > > case TYPE_PACK_EXPANSION: > > > case FIXED_POINT_TYPE: > > > case NULLPTR_TYPE: > > > + case PACK_INDEX_TYPE: > > > dump_type (pp, t, flags); > > > pp->set_padding (pp_before); > > > break; > > > @@ -1220,6 +1228,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, > > > int flags) > > > case TYPE_PACK_EXPANSION: > > > case FIXED_POINT_TYPE: > > > case NULLPTR_TYPE: > > > + case PACK_INDEX_TYPE: > > > break; > > > default: > > > @@ -3103,6 +3112,13 @@ dump_expr (cxx_pretty_printer *pp, tree t, int > > > flags) > > > pp->expression (t); > > > break; > > > + case PACK_INDEX_EXPR: > > > + pp->expression (PACK_INDEX_PACK (t)); > > > + pp_cxx_left_bracket (pp); > > > + pp->expression (PACK_INDEX_INDEX (t)); > > > + pp_cxx_right_bracket (pp); > > > + break; > > > + > > > case TRUTH_AND_EXPR: > > > case TRUTH_OR_EXPR: > > > case TRUTH_XOR_EXPR: > > > diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc > > > index 4d46c0917a9..c103b50b1f1 100644 > > > --- a/gcc/cp/mangle.cc > > > +++ b/gcc/cp/mangle.cc > > > @@ -2669,6 +2669,12 @@ write_type (tree type) > > > "use library traits instead", type); > > > break; > > > + case PACK_INDEX_TYPE: > > > + /* TODO Mangle pack indexing > > > + <https://github.com/itanium-cxx-abi/cxx-abi/issues/175>. */ > > > + sorry ("mangling type pack index"); > > > + break; > > > + > > > case LANG_TYPE: > > > /* fall through. */ > > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc > > > index 9323023ff7f..2ef6d8a6d82 100644 > > > --- a/gcc/cp/module.cc > > > +++ b/gcc/cp/module.cc > > > @@ -9209,6 +9209,11 @@ trees_out::type_node (tree type) > > > tree_node (PACK_EXPANSION_EXTRA_ARGS (type)); > > > break; > > > + case PACK_INDEX_TYPE: > > > + tree_node (PACK_INDEX_PACK (type)); > > > + tree_node (PACK_INDEX_INDEX (type)); > > > + break; > > > + > > > case TYPENAME_TYPE: > > > { > > > tree_node (TYPE_CONTEXT (type)); > > > @@ -9776,6 +9781,15 @@ trees_in::tree_node (bool is_use) > > > } > > > break; > > > + case PACK_INDEX_TYPE: > > > + { > > > + tree pack = tree_node (); > > > + tree index = tree_node (); > > > + if (!get_overrun ()) > > > + res = make_pack_index (pack, index); > > > + } > > > + break; > > > + > > > case TYPENAME_TYPE: > > > { > > > tree ctx = tree_node (); > > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > > > index c1375ecdbb5..e562ba723ad 100644 > > > --- a/gcc/cp/parser.cc > > > +++ b/gcc/cp/parser.cc > > > @@ -5739,6 +5739,54 @@ cp_parser_fold_expression (cp_parser *parser, tree > > > expr1) > > > return finish_binary_fold_expr (loc, expr1, expr2, op); > > > } > > > +/* Parse a pack-index-specifier: > > > + > > > + pack-index-specifier: > > > + typedef-name ... [ constant-expression ] > > > + > > > + or a pack-index-expression: > > > + > > > + pack-index-expression: > > > + id-expression ... [ constant-expression ] > > > + > > > + PACK is the parsed typedef-name or the id-expression. Returns > > > + either a PACK_INDEX_TYPE or PACK_INDEX_EXPR. */ > > > + > > > +static tree > > > +cp_parser_pack_index (cp_parser *parser, tree pack) > > > +{ > > > + if (cxx_dialect < cxx26) > > > + pedwarn (cp_lexer_peek_token (parser->lexer)->location, > > > + OPT_Wc__26_extensions, "pack indexing only available with " > > > + "%<-std=c++2c%> or %<-std=gnu++2c%>"); > > > + /* Consume the '...' token. */ > > > + cp_lexer_consume_token (parser->lexer); > > > + /* Consume the '['. */ > > > + cp_lexer_consume_token (parser->lexer); > > > + > > > + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) > > > + { > > > + error_at (cp_lexer_peek_token (parser->lexer)->location, > > > + "pack index missing"); > > > > Maybe cp_parser_error? > > Unsure. This: > > template<typename... Ts> > void foo(Ts...[]); > > then generates: > > error: variable or field 'foo' declared void > error: expected primary-expression before '...' token > error: pack index missing before ']' token > > which doesn't seem better. > > > > + cp_lexer_consume_token (parser->lexer); > > > + return error_mark_node; > > > + } > > > + > > > + tree index = cp_parser_constant_expression (parser, > > > + /*allow_non_constant_p=*/false, > > > + /*non_constant_p=*/nullptr, > > > + /*strict_p=*/true); > > > + /* Consume the ']'. */ > > > + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); > > > + > > > + if (TREE_CODE (pack) == TYPE_DECL) > > > + pack = TREE_TYPE (pack); > > > + pack = make_pack_expansion (pack); > > > + if (pack == error_mark_node) > > > + return error_mark_node; > > > + return make_pack_index (pack, index); > > > +} > > > + > > > /* Parse a primary-expression. > > > primary-expression: > > > @@ -6368,6 +6416,12 @@ cp_parser_primary_expression (cp_parser *parser, > > > = make_location (caret_loc, start_loc, finish_loc); > > > decl.set_location (combined_loc); > > > + > > > + /* "T...[constant-expression]" is a C++26 pack-index-expression. */ > > > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > > > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > > > + decl = cp_parser_pack_index (parser, decl); > > > > Shouldn't this be in cp_parser_id_expression? > > It should, but I need to wait until after finish_id_expression, so that > DECL isn't just an identifier node. > > > > return decl; > > > } > > > @@ -6411,6 +6465,7 @@ missing_template_diag (location_t loc, diagnostic_t > > > diag_kind = DK_WARNING) > > > id-expression: > > > unqualified-id > > > qualified-id > > > + pack-index-expression > > > qualified-id: > > > :: [opt] nested-name-specifier template [opt] unqualified-id > > > @@ -6593,7 +6648,9 @@ cp_parser_id_expression (cp_parser *parser, > > > identifier > > > operator-function-id > > > conversion-function-id > > > - ~ class-name > > > + literal-operator-id > > > + ~ type-name > > > + ~ computed-type-specifier > > > > Hmm, seems we never implemented ~decltype. > > Looks like CWG 1753: <https://gcc.gnu.org/PR117450>. > > > > template-id > > > If TEMPLATE_KEYWORD_P is TRUE, we have just seen the `template' > > > @@ -6900,6 +6957,14 @@ cp_parser_unqualified_id (cp_parser* parser, > > > "typedef-name %qD used as destructor declarator", > > > type_decl); > > > + /* "~T...[N]" is a C++26 pack-index-specifier. */ > > > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > > > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > > > + { > > > + type_decl = cp_parser_pack_index (parser, type_decl); > > > + return build_min_nt_loc (loc, BIT_NOT_EXPR, type_decl); > > > + } > > > > > return build_min_nt_loc (loc, BIT_NOT_EXPR, TREE_TYPE > > > (type_decl)); > > > } > > > @@ -6970,9 +7035,10 @@ check_template_keyword_in_nested_name_spec (tree > > > name) > > > class-or-namespace-name :: nested-name-specifier [opt] > > > class-or-namespace-name :: template nested-name-specifier [opt] > > > - nested-name-specifier: [C++0x] > > > + nested-name-specifier: [C++11] > > > type-name :: > > > namespace-name :: > > > + computed-type-specifier :: > > > nested-name-specifier identifier :: > > > nested-name-specifier template [opt] simple-template-id :: > > > @@ -7080,6 +7146,10 @@ cp_parser_nested_name_specifier_opt (cp_parser > > > *parser, > > > } > > > if (token->type != CPP_SCOPE > > > + /* See if a pack-index-specifier follows. */ > > > + && !(token->type == CPP_ELLIPSIS > > > + && cp_lexer_peek_nth_token (parser->lexer, 3)->type > > > + == CPP_OPEN_SQUARE) > > > > Also update the comment a few lines up? > > Done. > > > > /* If the following token is neither a `<' (to begin a > > > template-id), nor a `::', then we are not looking at a > > > nested-name-specifier. */ > > > > > && !cp_parser_nth_token_starts_template_argument_list_p > > > (parser, 2)) > > > break; > > > @@ -7127,6 +7197,12 @@ cp_parser_nested_name_specifier_opt (cp_parser > > > *parser, > > > check_dependency_p, > > > type_p, > > > is_declaration); > > > + > > > + /* "T...[constant-expression]" is a C++26 pack-index-specifier. */ > > > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > > > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > > > + new_scope = cp_parser_pack_index (parser, new_scope); > > > > Shouldn't this be in cp_parser_qualifying_entity? > > It could. Moved. > > > > /* Look for the `::' token. */ > > > cp_parser_require (parser, CPP_SCOPE, RT_SCOPE); > > > @@ -17410,6 +17486,11 @@ cp_parser_decltype_expr (cp_parser *parser, > > > /* Parse a full expression. */ > > > expr = cp_parser_expression (parser, /*pidk=*/NULL, > > > /*cast_p=*/false, > > > /*decltype_p=*/true); > > > + /* A pack indexing is an id-expression. cp_parser_expression does > > > not > > > + tell us if the pack indexing was wrapped in (), so we use the > > > + PACK_INDEX_PARENTHESIZED_P flag to track that. */ > > > + if (PACK_INDEX_P (expr)) > > > + id_expression_or_member_access_p = true; > > > > Since it's an id-expression, I'd think it should have been handled in the > > earlier call to cp_parser_id_expression. > > As mentioned above, I need to wait for the finish_id_expression call. > But still, I shouldn't have to wait till the cp_parser_expression call; > we should handle a pack indexing earlier in the function. Changed. > > > > return expr; > > > @@ -17938,13 +18019,17 @@ cp_parser_mem_initializer (cp_parser* parser) > > > /* Parse a mem-initializer-id. > > > mem-initializer-id: > > > - :: [opt] nested-name-specifier [opt] class-name > > > - decltype-specifier (C++11) > > > + class-or-decltype > > > identifier > > > + class-or-decltype: > > > + nested-name-specifier [opt] type-name > > > + nested-name-specifier template simple-template-id > > > + computed-type-specifier > > > > > Returns a TYPE indicating the class to be initialized for the first > > > - production (and the second in C++11). Returns an IDENTIFIER_NODE > > > - indicating the data member to be initialized for the last production. > > > */ > > > + production. Returns an IDENTIFIER_NODE indicating the data member to > > > + be initialized for the second production. */ > > > static tree > > > cp_parser_mem_initializer_id (cp_parser* parser) > > > @@ -18015,10 +18100,16 @@ cp_parser_mem_initializer_id (cp_parser* parser) > > > /*class_head_p=*/false, > > > /*is_declaration=*/true); > > > /* If we found one, we're done. */ > > > - if (cp_parser_parse_definitely (parser)) > > > - return id; > > > - /* Otherwise, look for an ordinary identifier. */ > > > - return cp_parser_identifier (parser); > > > + if (!cp_parser_parse_definitely (parser)) > > > + /* Otherwise, look for an ordinary identifier. */ > > > + id = cp_parser_identifier (parser); > > > + > > > + /* ": T...[N]" is a C++26 pack-index-specifier. */ > > > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > > > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > > > + id = cp_parser_pack_index (parser, id); > > > + return id; > > > } > > > /* Overloading [gram.over] */ > > > @@ -20436,11 +20527,11 @@ cp_parser_type_specifier (cp_parser* parser, > > > C++11 Extension: > > > simple-type-specifier: > > > - auto > > > - decltype ( expression ) > > > char16_t > > > char32_t > > > __underlying_type ( type-id ) > > > + computed-type-specifier > > > + placeholder-type-specifier > > > C++17 extension: > > > @@ -20822,6 +20913,13 @@ cp_parser_simple_type_specifier (cp_parser* > > > parser, > > > type = NULL_TREE; > > > } > > > + /* "T...[constant-expression]" is a C++26 pack-index-specifier. */ > > > + if (type > > > + && type != error_mark_node > > > + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > > > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > > > + type = cp_parser_pack_index (parser, type); > > > + > > > if (!type && flag_concepts && decl_specs) > > > { > > > /* Try for a type-constraint with template arguments. We > > > check > > > @@ -29103,12 +29201,21 @@ cp_parser_base_clause (cp_parser* parser) > > > /* Parse a base-specifier. > > > base-specifier: > > > - attribute-specifier-seq [opt] :: [opt] nested-name-specifier [opt] > > > - class-name > > > - attribute-specifier-seq [opt] virtual access-specifier [opt] :: > > > [opt] > > > - nested-name-specifier [opt] class-name > > > - attribute-specifier-seq [opt] access-specifier virtual [opt] :: > > > [opt] > > > - nested-name-specifier [opt] class-name > > > + attribute-specifier-seq [opt] class-or-decltype > > > + attribute-specifier-seq [opt] virtual access-specifier [opt] > > > + class-or-decltype > > > + attribute-specifier-seq [opt] access-specifier virtual [opt] > > > + class-or-decltype > > > + > > > + class-or-decltype: > > > + nested-name-specifier [opt] type-name > > > + nested-name-specifier template simple-template-id > > > + computed-type-specifier > > > + > > > + access-specifier: > > > + private > > > + protected > > > + public > > > Returns a TREE_LIST. The TREE_PURPOSE will be one of > > > ACCESS_{DEFAULT,PUBLIC,PROTECTED,PRIVATE}_[VIRTUAL]_NODE to > > > @@ -29237,6 +29344,10 @@ cp_parser_base_specifier (cp_parser* parser) > > > /*class_head_p=*/false, > > > /*is_declaration=*/true); > > > type = TREE_TYPE (type); > > > + /* ": T...[constant-expression]" is a C++26 pack-index-specifier. > > > */ > > > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > > > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > > > + type = cp_parser_pack_index (parser, type); > > > > Seems like we could replace a lot of this function with a call to > > cp_parser_class_or_decltype, if it existed. But that doesn't need to happen > > in this patch. > > That would be nice. > > > > } > > > if (type == error_mark_node) > > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > > > index 15d6d82f32f..6a8d275c4a7 100644 > > > --- a/gcc/cp/pt.cc > > > +++ b/gcc/cp/pt.cc > > > @@ -1789,6 +1789,11 @@ iterative_hash_template_arg (tree arg, hashval_t > > > val) > > > val = iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), > > > val); > > > return iterative_hash_template_arg (PACK_EXPANSION_EXTRA_ARGS > > > (arg), val); > > > + case PACK_INDEX_TYPE: > > > + case PACK_INDEX_EXPR: > > > + val = iterative_hash_template_arg (PACK_INDEX_PACK (arg), val); > > > + return iterative_hash_template_arg (PACK_INDEX_INDEX (arg), val); > > > + > > > case TYPE_ARGUMENT_PACK: > > > case NONTYPE_ARGUMENT_PACK: > > > return iterative_hash_template_arg (ARGUMENT_PACK_ARGS (arg), > > > val); > > > @@ -4031,6 +4036,15 @@ find_parameter_packs_r (tree *tp, int > > > *walk_subtrees, void* data) > > > *walk_subtrees = 0; > > > return NULL_TREE; > > > + case PACK_INDEX_TYPE: > > > + case PACK_INDEX_EXPR: > > > + /* We can have an expansion of an expansion, such as > > > "Ts...[Is]...", > > > + so do look into the index. */ > > > + cp_walk_tree (&PACK_INDEX_INDEX (t), &find_parameter_packs_r, ppd, > > > + ppd->visited); > > > + *walk_subtrees = 0; > > > + return NULL_TREE; > > > > Do we need to handle these specifically here? I'd think the handling in > > cp_walk_subtrees would be enough. > > I think I do, otherwise the Ts...[Is]... test doesn't work. > It is used when calling check_for_bare_parameter_packs. > > > > case INTEGER_TYPE: > > > cp_walk_tree (&TYPE_MAX_VALUE (t), &find_parameter_packs_r, > > > ppd, ppd->visited); > > > @@ -4257,6 +4271,33 @@ make_pack_expansion (tree arg, tsubst_flags_t > > > complain) > > > return result; > > > } > > > +/* Create a PACK_INDEX_* using the pack expansion PACK and index INDEX. > > > */ > > > + > > > +tree > > > +make_pack_index (tree pack, tree index) > > > +{ > > > + bool for_types; > > > + if (TREE_CODE (pack) == TYPE_PACK_EXPANSION) > > > + for_types = true; > > > + else if (TREE_CODE (pack) == EXPR_PACK_EXPANSION) > > > + for_types = false; > > > + else > > > + { > > > + /* Maybe we've already partially substituted the pack. */ > > > + gcc_checking_assert (TREE_CODE (pack) == TREE_VEC); > > > + for_types = TYPE_P (TREE_VEC_ELT (pack, 0)); > > > + } > > > + > > > + tree t = (for_types > > > + ? cxx_make_type (PACK_INDEX_TYPE) > > > + : make_node (PACK_INDEX_EXPR)); > > > + PACK_INDEX_PACK (t) = pack; > > > + PACK_INDEX_INDEX (t) = index; > > > + if (TREE_CODE (t) == PACK_INDEX_TYPE) > > > + SET_TYPE_STRUCTURAL_EQUALITY (t); > > > + return t; > > > +} > > > + > > > /* Checks T for any "bare" parameter packs, which have not yet been > > > expanded, and issues an error if any are found. This operation can > > > only be done on full expressions or types (e.g., an expression > > > @@ -13645,11 +13686,12 @@ add_extra_args (tree extra, tree args, > > > tsubst_flags_t complain, tree in_decl) > > > return args; > > > } > > > -/* Substitute ARGS into T, which is an pack expansion > > > - (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a > > > +/* Substitute ARGS into T, which is a pack expansion > > > + (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a > > > TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node > > > (if only a partial substitution could be performed) or > > > ERROR_MARK_NODE if there was an error. */ > > > + > > > tree > > > tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, > > > tree in_decl) > > > @@ -13950,6 +13992,25 @@ tsubst_pack_expansion (tree t, tree args, > > > tsubst_flags_t complain, > > > return result; > > > } > > > +/* Substitute ARGS into T, which is a pack index (i.e., PACK_INDEX_TYPE > > > or > > > + PACK_INDEX_EXPR). Returns a single type or expression, a PACK_INDEX_* > > > + node if only a partial substitution could be performed, or > > > ERROR_MARK_NODE > > > + if there was an error. */ > > > + > > > +tree > > > +tsubst_pack_index (tree t, tree args, tsubst_flags_t complain, tree > > > in_decl) > > > +{ > > > + tree pack = PACK_INDEX_PACK (t); > > > + if (PACK_EXPANSION_P (pack)) > > > + pack = tsubst_pack_expansion (pack, args, complain, in_decl); > > > + tree index = tsubst_expr (PACK_INDEX_INDEX (t), args, complain, > > > in_decl); > > > + if (!value_dependent_expression_p (index) && TREE_CODE (pack) == > > > TREE_VEC) > > > + return pack_index_element (index, pack, PACK_INDEX_PARENTHESIZED_P > > > (t), > > > + complain); > > > + else > > > + return make_pack_index (pack, index); > > > +} > > > + > > > /* Make an argument pack out of the TREE_VEC VEC. */ > > > static tree > > > @@ -16338,7 +16399,8 @@ tsubst (tree t, tree args, tsubst_flags_t > > > complain, tree in_decl) > > > && code != TEMPLATE_PARM_INDEX > > > && code != IDENTIFIER_NODE > > > && code != FUNCTION_TYPE > > > - && code != METHOD_TYPE) > > > + && code != METHOD_TYPE > > > + && code != PACK_INDEX_TYPE) > > > type = tsubst (type, args, complain, in_decl); > > > if (type == error_mark_node) > > > return error_mark_node; > > > @@ -16898,9 +16960,15 @@ tsubst (tree t, tree args, tsubst_flags_t > > > complain, tree in_decl) > > > ctx = tsubst_pack_expansion (ctx, args, > > > complain | tf_qualifying_scope, > > > in_decl); > > > - if (ctx == error_mark_node > > > - || TREE_VEC_LENGTH (ctx) > 1) > > > + if (ctx == error_mark_node) > > > return error_mark_node; > > > + if (TREE_VEC_LENGTH (ctx) > 1) > > > + { > > > + if (complain & tf_error) > > > + error ("%qD expanded to more than one element", > > > + TYPENAME_TYPE_FULLNAME (t)); > > > + return error_mark_node; > > > + } > > > if (TREE_VEC_LENGTH (ctx) == 0) > > > { > > > if (complain & tf_error) > > > @@ -17042,12 +17110,17 @@ tsubst (tree t, tree args, tsubst_flags_t > > > complain, tree in_decl) > > > else > > > { > > > bool id = DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t); > > > - if (id && TREE_CODE (DECLTYPE_TYPE_EXPR (t)) == BIT_NOT_EXPR > > > - && EXPR_P (type)) > > > - /* In a template ~id could be either a complement expression > > > - or an unqualified-id naming a destructor; if instantiating > > > - it produces an expression, it's not an id-expression or > > > - member access. */ > > > + tree op = DECLTYPE_TYPE_EXPR (t); > > > + if (id > > > + /* In a template ~id could be either a complement expression > > > + or an unqualified-id naming a destructor; if instantiating > > > + it produces an expression, it's not an id-expression or > > > + member access. */ > > > + && ((TREE_CODE (op) == BIT_NOT_EXPR && EXPR_P (type)) > > > + /* If the pack indexing was wrapped in (), it's not an > > > + id-expression, either. */ > > > + || (PACK_INDEX_P (op) > > > + && PACK_INDEX_PARENTHESIZED_P (op)))) > > > > I still think DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P should be enough in > > this case; I would think we only need PACK_INDEX_PARENTHESIZED_P for > > tsubst_pack_index to pass to pack_index_element. > > Looks like I don't need this change anymore. Yay! > > > > id = false; > > > type = finish_decltype_type (type, id, complain); > > > } > > > @@ -17075,6 +17148,9 @@ tsubst (tree t, tree args, tsubst_flags_t > > > complain, tree in_decl) > > > case NONTYPE_ARGUMENT_PACK: > > > return tsubst_argument_pack (t, args, complain, in_decl); > > > + case PACK_INDEX_TYPE: > > > + return tsubst_pack_index (t, args, complain, in_decl); > > > + > > > case VOID_CST: > > > case INTEGER_CST: > > > case REAL_CST: > > > @@ -21776,6 +21852,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t > > > complain, tree in_decl) > > > RETURN (r); > > > } > > > + case PACK_INDEX_EXPR: > > > + RETURN (tsubst_pack_index (t, args, complain, in_decl)); > > > + > > > case EXPR_PACK_EXPANSION: > > > error ("invalid use of pack expansion expression"); > > > RETURN (error_mark_node); > > > @@ -28116,8 +28195,9 @@ dependent_type_p_r (tree type) > > > } > > > /* All TYPE_PACK_EXPANSIONs are dependent, because parameter packs > > > must > > > - be template parameters. */ > > > - if (TREE_CODE (type) == TYPE_PACK_EXPANSION) > > > + be template parameters. This includes pack-index-specifiers. */ > > > + if (TREE_CODE (type) == TYPE_PACK_EXPANSION > > > + || TREE_CODE (type) == PACK_INDEX_TYPE) > > > return true; > > > if (TREE_CODE (type) == DEPENDENT_OPERATOR_TYPE) > > > @@ -28740,8 +28820,10 @@ type_dependent_expression_p (tree expression) > > > && uses_outer_template_parms_in_constraints (expression)) > > > return true; > > > - /* Always dependent, on the number of arguments if nothing else. */ > > > - if (TREE_CODE (expression) == EXPR_PACK_EXPANSION) > > > + /* Always dependent, on the number of arguments if nothing else. This > > > + includes pack-index-expressions. */ > > > + if (TREE_CODE (expression) == EXPR_PACK_EXPANSION > > > + || TREE_CODE (expression) == PACK_INDEX_EXPR) > > > return true; > > > if (TREE_TYPE (expression) == unknown_type_node) > > > diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc > > > index 95c7a69e27c..74152c9476d 100644 > > > --- a/gcc/cp/ptree.cc > > > +++ b/gcc/cp/ptree.cc > > > @@ -193,6 +193,11 @@ cxx_print_type (FILE *file, tree node, int indent) > > > print_node (file, "args", PACK_EXPANSION_EXTRA_ARGS (node), > > > indent + 4); > > > return; > > > + case PACK_INDEX_TYPE: > > > + print_node (file, "pack", PACK_INDEX_PACK (node), indent + 4); > > > + print_node (file, "index", PACK_INDEX_INDEX (node), indent + 4); > > > + return; > > > + > > > default: > > > return; > > > } > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > > index ab8614e376d..0b7cd514742 100644 > > > --- a/gcc/cp/semantics.cc > > > +++ b/gcc/cp/semantics.cc > > > @@ -2453,6 +2453,8 @@ finish_parenthesized_expr (cp_expr expr) > > > tree stripped_expr = tree_strip_any_location_wrapper (expr); > > > if (TREE_CODE (stripped_expr) == STRING_CST) > > > PAREN_STRING_LITERAL_P (stripped_expr) = 1; > > > + else if (PACK_INDEX_P (stripped_expr)) > > > + PACK_INDEX_PARENTHESIZED_P (stripped_expr) = true; > > > expr = cp_expr (force_paren_expr (expr), expr.get_location ()); > > > @@ -4848,24 +4850,38 @@ finish_type_pack_element (tree idx, tree types, > > > tsubst_flags_t complain) > > > if (TREE_CODE (idx) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE > > > (idx))) > > > { > > > if (complain & tf_error) > > > - error ("%<__type_pack_element%> index is not an integral constant"); > > > + error ("pack index is not an integral constant"); > > > return error_mark_node; > > > } > > > if (tree_int_cst_sgn (idx) < 0) > > > { > > > if (complain & tf_error) > > > - error ("%<__type_pack_element%> index is negative"); > > > + error ("pack index is negative"); > > > return error_mark_node; > > > } > > > if (wi::to_widest (idx) >= TREE_VEC_LENGTH (types)) > > > { > > > if (complain & tf_error) > > > - error ("%<__type_pack_element%> index is out of range"); > > > + error ("pack index is out of range"); > > > return error_mark_node; > > > } > > > return TREE_VEC_ELT (types, tree_to_shwi (idx)); > > > } > > > +/* In a pack-index T...[N], return the element at index IDX within TYPES. > > > + PARENTHESIZED_P is true iff the pack index was wrapped in (). */ > > > + > > > +tree > > > +pack_index_element (tree idx, tree types, bool parenthesized_p, > > > + tsubst_flags_t complain) > > > +{ > > > + tree r = finish_type_pack_element (idx, types, complain); > > > + if (parenthesized_p) > > > + /* For the benefit of decltype(auto). */ > > > + r = force_paren_expr (r); > > > + return r; > > > +} > > > + > > > /* Implement the __direct_bases keyword: Return the direct base classes > > > of type. */ > > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > > > index 911260685f1..53fcbc7273e 100644 > > > --- a/gcc/cp/tree.cc > > > +++ b/gcc/cp/tree.cc > > > @@ -4245,6 +4245,15 @@ cp_tree_equal (tree t1, tree t2) > > > return false; > > > return true; > > > + case PACK_INDEX_EXPR: > > > + if (!cp_tree_equal (PACK_INDEX_PACK (t1), > > > + PACK_INDEX_PACK (t2))) > > > + return false; > > > + if (!cp_tree_equal (PACK_INDEX_INDEX (t1), > > > + PACK_INDEX_INDEX (t2))) > > > + return false; > > > + return true; > > > + > > > case COMPONENT_REF: > > > /* If we're comparing contract conditions of overrides, member > > > references > > > compare equal if they designate the same member. */ > > > @@ -5585,6 +5594,13 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, > > > walk_tree_fn func, > > > *walk_subtrees_p = 0; > > > break; > > > + case PACK_INDEX_TYPE: > > > + case PACK_INDEX_EXPR: > > > + WALK_SUBTREE (PACK_INDEX_PACK (t)); > > > + WALK_SUBTREE (PACK_INDEX_INDEX (t)); > > > + *walk_subtrees_p = 0; > > > + break; > > > + > > > case CAST_EXPR: > > > case REINTERPRET_CAST_EXPR: > > > case STATIC_CAST_EXPR: > > > diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc > > > index 6ce1bb61fe7..06c632b9ee2 100644 > > > --- a/gcc/cp/typeck.cc > > > +++ b/gcc/cp/typeck.cc > > > @@ -1623,6 +1623,12 @@ structural_comptypes (tree t1, tree t2, int strict) > > > && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1), > > > PACK_EXPANSION_EXTRA_ARGS (t2))); > > > + case PACK_INDEX_TYPE: > > > + return (cp_tree_equal (PACK_INDEX_PACK (t1), > > > + PACK_INDEX_PACK (t2)) > > > + && cp_tree_equal (PACK_INDEX_INDEX (t1), > > > + PACK_INDEX_INDEX (t2))); > > > + > > > case DECLTYPE_TYPE: > > > if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1) > > > != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)) > > > > ...testsuite... > > > > I'm not seeing a test for https://eel.is/c++draft/diff#cpp23.dcl.dcl-2 or > > the code to handle this case differently in C++23 vs 26. > > Ah, right. I've added the test (pack-indexing11.C) but we don't > compile it C++23 as we should due to: > > pack-indexing11.C:7:13: error: expected ',' or '...' before '[' token > 7 | void f(T... [1]); > | ^ > > which seems like a bug. Opened <https://gcc.gnu.org/PR117472>. > > Is fixing that a requirement for this patch? > > > > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing7.C > > > b/gcc/testsuite/g++.dg/cpp26/pack-indexing7.C > > > new file mode 100644 > > > index 00000000000..06e2a3d0dc7 > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing7.C > > > @@ -0,0 +1,16 @@ > > > +// P2662R3 - Pack Indexing > > > +// PR c++/113798 > > > +// { dg-do compile { target c++26 } } > > > + > > > +template <int I, auto...Ts> > > > +decltype(Ts...[I]) > > > +foo () // { dg-message "sorry, unimplemented: > > > mangling" } > > > > This should be dg-bogus/xfail. > > Done. > > > > +{ > > > + return Ts...[I]; > > > +} > > > + > > > +int > > > +g () > > > +{ > > > + return foo<2, 0, 1, 42>(); > > > +} > > > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing8.C > > > b/gcc/testsuite/g++.dg/cpp26/pack-indexing8.C > > > new file mode 100644 > > > index 00000000000..2b1b67c0841 > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing8.C > > > @@ -0,0 +1,23 @@ > > > +// P2662R3 - Pack Indexing > > > +// PR c++/113798 > > > +// { dg-do run { target c++26 } } > > > + > > > +#include <initializer_list> > > > + > > > +template<typename... Ts> > > > +int > > > +g (auto... Is) > > > +{ > > > + std::initializer_list<Ts...[0]> l{ Is...[0], Is...[1], Is...[2], > > > Is...[3], Is...[4] }; > > > + int sum = 0; > > > + for (auto x : l) > > > + sum += x; > > > + return sum; > > > +} > > > + > > > +int > > > +main () > > > +{ > > > + if (g<int> (1, 2, 3, 4, 5) != 15) > > > + __builtin_abort (); > > > +} > > > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing9.C > > > b/gcc/testsuite/g++.dg/cpp26/pack-indexing9.C > > > new file mode 100644 > > > index 00000000000..468ae9dc4d1 > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing9.C > > > @@ -0,0 +1,27 @@ > > > +// P2662R3 - Pack Indexing > > > +// PR c++/113798 > > > +// { dg-do compile { target c++26 } } > > > +// From <https://github.com/itanium-cxx-abi/cxx-abi/issues/175>. > > > + > > > +template <class... T> struct tuple { > > > + template <unsigned I> T...[I] get(); // { dg-message "sorry, > > > unimplemented: mangling" } > > > > dg-bogus/xfail again. > > Done. > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > -- >8 -- > This patch implements C++26 Pack Indexing, as described in > <https://wg21.link/P2662R3>. > > The issue discussing how to mangle pack indexes has not been resolved > yet <https://github.com/itanium-cxx-abi/cxx-abi/issues/175> and I've > made no attempt to address it so far. > > Unlike v1, which used augmented TYPE/EXPR_PACK_EXPANSION codes, this > version introduces two new codes: PACK_INDEX_EXPR and PACK_INDEX_TYPE. > Both carry two operands: the pack expansion and the index. They are > handled in tsubst_pack_index: substitute the index and the pack and > then extract the element from the vector (if possible). > > To handle pack indexing in a decltype or with decltype(auto), there is > also the new PACK_INDEX_PARENTHESIZED_P flag. > > With this feature, it's valid to write something like > > using U = tmpl<Ts...[Is]...>; > > where we first expand the template argument into > > Ts...[Is#0], Ts...[Is#1], ... > > and then substitute each individual pack index. > > PR c++/113798 > > gcc/cp/ChangeLog: > > * constexpr.cc (potential_constant_expression_1) <case PACK_INDEX_EXPR>: > New case. > * cp-objcp-common.cc (cp_common_init_ts): Mark PACK_INDEX_TYPE and > PACK_INDEX_EXPR. > * cp-tree.def (PACK_INDEX_TYPE): New. > (PACK_INDEX_EXPR): New. > * cp-tree.h (WILDCARD_TYPE_P): Also check PACK_INDEX_TYPE. > (PACK_INDEX_CHECK): Define. > (PACK_INDEX_P): Define. > (PACK_INDEX_PACK): Define. > (PACK_INDEX_INDEX): Define. > (PACK_INDEX_PARENTHESIZED_P): Define. > (make_pack_index): Declare. > (pack_index_element): Declare. > * cxx-pretty-print.cc (cxx_pretty_printer::expression) <case > PACK_INDEX_EXPR>: New case. > (cxx_pretty_printer::type_id) <case PACK_INDEX_TYPE>: New case. > * error.cc (dump_type) <case PACK_INDEX_TYPE>: New case. > (dump_type_prefix): Handle PACK_INDEX_TYPE. > (dump_type_suffix): Likewise. > (dump_expr) <case PACK_INDEX_EXPR>: New case. > * mangle.cc (write_type) <case PACK_INDEX_TYPE>: New case. > * module.cc (trees_out::type_node) <case PACK_INDEX_TYPE>: New case. > (trees_in::tree_node) <case PACK_INDEX_TYPE>: New case. > * parser.cc (cp_parser_pack_index): New. > (cp_parser_primary_expression): Handle a C++26 pack-index-expression. > (cp_parser_unqualified_id): Handle a C++26 pack-index-specifier. > (cp_parser_nested_name_specifier_opt): See if a pack-index-specifier > follows. > (cp_parser_qualifying_entity): Handle a C++26 pack-index-specifier. > (cp_parser_decltype_expr): Set id_expression_or_member_access_p for > pack indexing. > (cp_parser_mem_initializer_id): Handle a C++26 pack-index-specifier. > (cp_parser_simple_type_specifier): Likewise. > (cp_parser_base_specifier): Likewise. > * pt.cc (iterative_hash_template_arg) <case PACK_INDEX_TYPE, > PACK_INDEX_EXPR>: New case. > (find_parameter_packs_r) <case PACK_INDEX_TYPE, PACK_INDEX_EXPR>: New > case. > (make_pack_index): New. > (tsubst_pack_index): New. > (tsubst): Avoid tsubst on PACK_INDEX_TYPE. > <case TYPENAME_TYPE>: Add a call to error. > <case PACK_INDEX_TYPE>: New case. > (tsubst_expr) <case PACK_INDEX_EXPR>: New case. > (dependent_type_p_r): Return true for PACK_INDEX_TYPE. > (type_dependent_expression_p): Return true for PACK_INDEX_EXPR. > * ptree.cc (cxx_print_type) <case PACK_INDEX_TYPE>: New case. > * semantics.cc (finish_parenthesized_expr): Set > PACK_INDEX_PARENTHESIZED_P for PACK_INDEX_EXPR. > (finish_type_pack_element): Adjust error messages. > (pack_index_element): New. > * tree.cc (cp_tree_equal) <case PACK_INDEX_EXPR>: New case. > (cp_walk_subtrees) <case PACK_INDEX_TYPE, PACK_INDEX_EXPR>: New case. > * typeck.cc (structural_comptypes) <case PACK_INDEX_TYPE>: New case. > > libstdc++-v3/ChangeLog: > > * testsuite/20_util/tuple/element_access/get_neg.cc: Adjust > dg-prune-output. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp26/pack-indexing1.C: New test. > * g++.dg/cpp26/pack-indexing2.C: New test. > * g++.dg/cpp26/pack-indexing3.C: New test. > * g++.dg/cpp26/pack-indexing4.C: New test. > * g++.dg/cpp26/pack-indexing5.C: New test. > * g++.dg/cpp26/pack-indexing6.C: New test. > * g++.dg/cpp26/pack-indexing7.C: New test. > * g++.dg/cpp26/pack-indexing8.C: New test. > * g++.dg/cpp26/pack-indexing9.C: New test. > * g++.dg/cpp26/pack-indexing10.C: New test. > * g++.dg/cpp26/pack-indexing11.C: New test. > * g++.dg/modules/pack-index-1_a.C: New test. > * g++.dg/modules/pack-index-1_b.C: New test. > --- > gcc/cp/constexpr.cc | 3 + > gcc/cp/cp-objcp-common.cc | 2 + > gcc/cp/cp-tree.def | 8 + > gcc/cp/cp-tree.h | 31 +++- > gcc/cp/cxx-pretty-print.cc | 14 ++ > gcc/cp/error.cc | 16 ++ > gcc/cp/mangle.cc | 6 + > gcc/cp/module.cc | 14 ++ > gcc/cp/parser.cc | 167 +++++++++++++++--- > gcc/cp/pt.cc | 96 +++++++++- > gcc/cp/ptree.cc | 5 + > gcc/cp/semantics.cc | 22 ++- > gcc/cp/tree.cc | 16 ++ > gcc/cp/typeck.cc | 6 + > gcc/testsuite/g++.dg/cpp26/pack-indexing1.C | 102 +++++++++++ > gcc/testsuite/g++.dg/cpp26/pack-indexing10.C | 15 ++ > gcc/testsuite/g++.dg/cpp26/pack-indexing11.C | 13 ++ > gcc/testsuite/g++.dg/cpp26/pack-indexing2.C | 111 ++++++++++++ > gcc/testsuite/g++.dg/cpp26/pack-indexing3.C | 41 +++++ > gcc/testsuite/g++.dg/cpp26/pack-indexing4.C | 65 +++++++ > gcc/testsuite/g++.dg/cpp26/pack-indexing5.C | 41 +++++ > gcc/testsuite/g++.dg/cpp26/pack-indexing6.C | 51 ++++++ > gcc/testsuite/g++.dg/cpp26/pack-indexing7.C | 16 ++ > gcc/testsuite/g++.dg/cpp26/pack-indexing8.C | 23 +++ > gcc/testsuite/g++.dg/cpp26/pack-indexing9.C | 27 +++ > gcc/testsuite/g++.dg/modules/pack-index-1_a.C | 18 ++ > gcc/testsuite/g++.dg/modules/pack-index-1_b.C | 15 ++ > .../20_util/tuple/element_access/get_neg.cc | 2 +- > 28 files changed, 906 insertions(+), 40 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing1.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing10.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing11.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing2.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing3.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing4.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing5.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing6.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing7.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing8.C > create mode 100644 gcc/testsuite/g++.dg/cpp26/pack-indexing9.C > create mode 100644 gcc/testsuite/g++.dg/modules/pack-index-1_a.C > create mode 100644 gcc/testsuite/g++.dg/modules/pack-index-1_b.C > > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc > index 71e6dc4ef32..818b9aa93ca 100644 > --- a/gcc/cp/constexpr.cc > +++ b/gcc/cp/constexpr.cc > @@ -9947,6 +9947,9 @@ potential_constant_expression_1 (tree t, bool > want_rval, bool strict, bool now, > case EXPR_PACK_EXPANSION: > return RECUR (PACK_EXPANSION_PATTERN (t), want_rval); > > + case PACK_INDEX_EXPR: > + return true; > + > case INDIRECT_REF: > { > tree x = TREE_OPERAND (t, 0); > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc > index 7a0636f1653..fe663ecaeb6 100644 > --- a/gcc/cp/cp-objcp-common.cc > +++ b/gcc/cp/cp-objcp-common.cc > @@ -642,6 +642,7 @@ cp_common_init_ts (void) > MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM); > MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM); > MARK_TS_TYPE_NON_COMMON (TYPE_PACK_EXPANSION); > + MARK_TS_TYPE_NON_COMMON (PACK_INDEX_TYPE); > > /* Statements. */ > MARK_TS_EXP (CLEANUP_STMT); > @@ -700,6 +701,7 @@ cp_common_init_ts (void) > MARK_TS_EXP (NONTYPE_ARGUMENT_PACK); > MARK_TS_EXP (UNARY_LEFT_FOLD_EXPR); > MARK_TS_EXP (UNARY_RIGHT_FOLD_EXPR); > + MARK_TS_EXP (PACK_INDEX_EXPR); > > /* Constraints. */ > MARK_TS_EXP (COMPOUND_REQ); > diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def > index 3de6923f771..fa445ec2781 100644 > --- a/gcc/cp/cp-tree.def > +++ b/gcc/cp/cp-tree.def > @@ -397,6 +397,14 @@ DEFTREECODE (TYPE_PACK_EXPANSION, "type_pack_expansion", > tcc_type, 0) > but will be used for expressions. */ > DEFTREECODE (EXPR_PACK_EXPANSION, "expr_pack_expansion", tcc_expression, 3) > > +/* Represents a pack index Ts...[I], yielding a type. PACK_INDEX_PACK is > + the pack expansion Ts, PACK_INDEX_INDEX the index I. */ > +DEFTREECODE (PACK_INDEX_TYPE, "pack_index_type", tcc_type, 0) > + > +/* Represents a pack index Ts...[I], yielding an expression. PACK_INDEX_PACK > + is the pack expansion Ts, PACK_INDEX_INDEX the index I. */ > +DEFTREECODE (PACK_INDEX_EXPR, "pack_index_expr", tcc_expression, 2) > + > /* Selects the Ith parameter out of an argument pack. This node will > be used when instantiating pack expansions; see > tsubst_pack_expansion. > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 92d1dba6a5c..c0b6cd0260a 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -451,6 +451,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; > ATOMIC_CONSTR_MAP_INSTANTIATED_P (in ATOMIC_CONSTR) > contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) > RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR) > + PACK_INDEX_PARENTHESIZED_P (in PACK_INDEX_*) > 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE) > TI_PENDING_TEMPLATE_FLAG. > TEMPLATE_PARMS_FOR_INLINE. > @@ -2258,7 +2259,8 @@ enum languages { lang_c, lang_cplusplus }; > || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \ > || TREE_CODE (T) == DECLTYPE_TYPE \ > || TREE_CODE (T) == TRAIT_TYPE \ > - || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE) > + || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE \ > + || TREE_CODE (T) == PACK_INDEX_TYPE) > > /* Nonzero if T is a class (or struct or union) type. Also nonzero > for template type parameters, typename types, and instantiated > @@ -4001,6 +4003,9 @@ struct GTY(()) lang_decl { > #define PACK_EXPANSION_CHECK(NODE) \ > TREE_CHECK2 (NODE, TYPE_PACK_EXPANSION, EXPR_PACK_EXPANSION) > > +#define PACK_INDEX_CHECK(NODE) \ > + TREE_CHECK2 (NODE, PACK_INDEX_TYPE, PACK_INDEX_EXPR) > + > /* Extracts the type or expression pattern from a TYPE_PACK_EXPANSION or > EXPR_PACK_EXPANSION. */ > #define PACK_EXPANSION_PATTERN(NODE) \ > @@ -4025,6 +4030,22 @@ struct GTY(()) lang_decl { > ? &TYPE_MAX_VALUE_RAW (NODE) \ > : &TREE_OPERAND ((NODE), 2)) > > +/* True if NODE is a pack index. */ > +#define PACK_INDEX_P(NODE) \ > + (TREE_CODE (NODE) == PACK_INDEX_TYPE \ > + || TREE_CODE (NODE) == PACK_INDEX_EXPR) > + > +/* For a pack index T...[N], the pack expansion 'T...'. */ > +#define PACK_INDEX_PACK(NODE) \ > + (TREE_CODE (PACK_INDEX_CHECK (NODE)) == PACK_INDEX_TYPE \ > + ? TREE_TYPE (NODE) : TREE_OPERAND (NODE, 0)) > + > +/* For a pack index T...[N], the index N. */ > +#define PACK_INDEX_INDEX(NODE) \ > + *(TREE_CODE (PACK_INDEX_CHECK (NODE)) == PACK_INDEX_TYPE \ > + ? &TYPE_MAX_VALUE_RAW (NODE) \ > + : &TREE_OPERAND ((NODE), 1)) > + > /* True iff this pack expansion is within a function context. */ > #define PACK_EXPANSION_LOCAL_P(NODE) \ > TREE_LANG_FLAG_0 (PACK_EXPANSION_CHECK (NODE)) > @@ -4042,6 +4063,11 @@ struct GTY(()) lang_decl { > #define PACK_EXPANSION_FORCE_EXTRA_ARGS_P(NODE) \ > TREE_LANG_FLAG_3 (PACK_EXPANSION_CHECK (NODE)) > > +/* Indicates whether a pack expansion has been parenthesized. Used for > + a pack expansion in a decltype. */ > +#define PACK_INDEX_PARENTHESIZED_P(NODE) \ > + TREE_LANG_FLAG_1 (TREE_CHECK (NODE, PACK_INDEX_EXPR)) > + > /* True iff the wildcard can match a template parameter pack. */ > #define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE) > > @@ -7581,6 +7607,7 @@ extern bool template_parameter_pack_p > (const_tree); > extern bool function_parameter_pack_p (const_tree); > extern bool function_parameter_expanded_from_pack_p (tree, tree); > extern tree make_pack_expansion (tree, tsubst_flags_t = > tf_warning_or_error); > +extern tree make_pack_index (tree, tree); > extern bool check_for_bare_parameter_packs (tree, location_t = > UNKNOWN_LOCATION); > extern tree build_template_info (tree, tree); > extern tree get_template_info (const_tree); > @@ -7906,6 +7933,8 @@ extern tree finish_underlying_type (tree); > extern tree calculate_bases (tree, tsubst_flags_t); > extern tree finish_bases (tree, bool); > extern tree calculate_direct_bases (tree, tsubst_flags_t); > +extern tree pack_index_element (tree, tree, bool, > + tsubst_flags_t); > extern tree finish_offsetof (tree, tree, location_t); > extern void finish_decl_cleanup (tree, tree); > extern void finish_eh_cleanup (tree); > diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc > index f4203123737..15d41b55557 100644 > --- a/gcc/cp/cxx-pretty-print.cc > +++ b/gcc/cp/cxx-pretty-print.cc > @@ -1220,6 +1220,13 @@ cxx_pretty_printer::expression (tree t) > pp_cxx_ws_string (this, "..."); > break; > > + case PACK_INDEX_EXPR: > + expression (PACK_INDEX_PACK (t)); > + pp_cxx_left_bracket (this); > + expression (PACK_INDEX_INDEX (t)); > + pp_cxx_right_bracket (this); > + break; > + > case UNARY_LEFT_FOLD_EXPR: > pp_cxx_unary_left_fold_expression (this, t); > break; > @@ -1920,6 +1927,13 @@ cxx_pretty_printer::type_id (tree t) > pp_cxx_ws_string (this, "..."); > break; > > + case PACK_INDEX_TYPE: > + type_id (PACK_INDEX_PACK (t)); > + pp_cxx_left_bracket (this); > + expression (PACK_INDEX_INDEX (t)); > + pp_cxx_right_bracket (this); > + break; > + > case TYPE_ARGUMENT_PACK: > { > tree args = ARGUMENT_PACK_ARGS (t); > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc > index 7ef79b90868..c62c9d7312e 100644 > --- a/gcc/cp/error.cc > +++ b/gcc/cp/error.cc > @@ -814,6 +814,13 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) > pp_cxx_ws_string (pp, "..."); > break; > > + case PACK_INDEX_TYPE: > + dump_type (pp, PACK_INDEX_PACK (t), flags); > + pp_cxx_left_bracket (pp); > + dump_expr (pp, PACK_INDEX_INDEX (t), flags & ~TFF_EXPR_IN_PARENS); > + pp_cxx_right_bracket (pp); > + break; > + > case TYPE_ARGUMENT_PACK: > dump_template_argument (pp, t, flags); > break; > @@ -1088,6 +1095,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int > flags) > case TYPE_PACK_EXPANSION: > case FIXED_POINT_TYPE: > case NULLPTR_TYPE: > + case PACK_INDEX_TYPE: > dump_type (pp, t, flags); > pp->set_padding (pp_before); > break; > @@ -1220,6 +1228,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int > flags) > case TYPE_PACK_EXPANSION: > case FIXED_POINT_TYPE: > case NULLPTR_TYPE: > + case PACK_INDEX_TYPE: > break; > > default: > @@ -3103,6 +3112,13 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) > pp->expression (t); > break; > > + case PACK_INDEX_EXPR: > + pp->expression (PACK_INDEX_PACK (t)); > + pp_cxx_left_bracket (pp); > + pp->expression (PACK_INDEX_INDEX (t)); > + pp_cxx_right_bracket (pp); > + break; > + > case TRUTH_AND_EXPR: > case TRUTH_OR_EXPR: > case TRUTH_XOR_EXPR: > diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc > index 4d46c0917a9..c103b50b1f1 100644 > --- a/gcc/cp/mangle.cc > +++ b/gcc/cp/mangle.cc > @@ -2669,6 +2669,12 @@ write_type (tree type) > "use library traits instead", type); > break; > > + case PACK_INDEX_TYPE: > + /* TODO Mangle pack indexing > + <https://github.com/itanium-cxx-abi/cxx-abi/issues/175>. */ > + sorry ("mangling type pack index"); > + break; > + > case LANG_TYPE: > /* fall through. */ > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc > index 4eefb2d3584..f6f87b7d80b 100644 > --- a/gcc/cp/module.cc > +++ b/gcc/cp/module.cc > @@ -9240,6 +9240,11 @@ trees_out::type_node (tree type) > tree_node (PACK_EXPANSION_EXTRA_ARGS (type)); > break; > > + case PACK_INDEX_TYPE: > + tree_node (PACK_INDEX_PACK (type)); > + tree_node (PACK_INDEX_INDEX (type)); > + break; > + > case TYPENAME_TYPE: > { > tree_node (TYPE_CONTEXT (type)); > @@ -9807,6 +9812,15 @@ trees_in::tree_node (bool is_use) > } > break; > > + case PACK_INDEX_TYPE: > + { > + tree pack = tree_node (); > + tree index = tree_node (); > + if (!get_overrun ()) > + res = make_pack_index (pack, index); > + } > + break; > + > case TYPENAME_TYPE: > { > tree ctx = tree_node (); > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index c1375ecdbb5..082456491a6 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -5739,6 +5739,54 @@ cp_parser_fold_expression (cp_parser *parser, tree > expr1) > return finish_binary_fold_expr (loc, expr1, expr2, op); > } > > +/* Parse a pack-index-specifier: > + > + pack-index-specifier: > + typedef-name ... [ constant-expression ] > + > + or a pack-index-expression: > + > + pack-index-expression: > + id-expression ... [ constant-expression ] > + > + PACK is the parsed typedef-name or the id-expression. Returns > + either a PACK_INDEX_TYPE or PACK_INDEX_EXPR. */ > + > +static tree > +cp_parser_pack_index (cp_parser *parser, tree pack) > +{ > + if (cxx_dialect < cxx26) > + pedwarn (cp_lexer_peek_token (parser->lexer)->location, > + OPT_Wc__26_extensions, "pack indexing only available with " > + "%<-std=c++2c%> or %<-std=gnu++2c%>"); > + /* Consume the '...' token. */ > + cp_lexer_consume_token (parser->lexer); > + /* Consume the '['. */ > + cp_lexer_consume_token (parser->lexer); > + > + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) > + { > + error_at (cp_lexer_peek_token (parser->lexer)->location, > + "pack index missing"); > + cp_lexer_consume_token (parser->lexer); > + return error_mark_node; > + } > + > + tree index = cp_parser_constant_expression (parser, > + /*allow_non_constant_p=*/false, > + /*non_constant_p=*/nullptr, > + /*strict_p=*/true); > + /* Consume the ']'. */ > + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); > + > + if (TREE_CODE (pack) == TYPE_DECL) > + pack = TREE_TYPE (pack); > + pack = make_pack_expansion (pack); > + if (pack == error_mark_node) > + return error_mark_node; > + return make_pack_index (pack, index); > +} > + > /* Parse a primary-expression. > > primary-expression: > @@ -6368,6 +6416,12 @@ cp_parser_primary_expression (cp_parser *parser, > = make_location (caret_loc, start_loc, finish_loc); > > decl.set_location (combined_loc); > + > + /* "T...[constant-expression]" is a C++26 pack-index-expression. */ > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > + decl = cp_parser_pack_index (parser, decl); > + > return decl; > } > > @@ -6411,6 +6465,7 @@ missing_template_diag (location_t loc, diagnostic_t > diag_kind = DK_WARNING) > id-expression: > unqualified-id > qualified-id > + pack-index-expression > > qualified-id: > :: [opt] nested-name-specifier template [opt] unqualified-id > @@ -6593,7 +6648,9 @@ cp_parser_id_expression (cp_parser *parser, > identifier > operator-function-id > conversion-function-id > - ~ class-name > + literal-operator-id > + ~ type-name > + ~ computed-type-specifier > template-id > > If TEMPLATE_KEYWORD_P is TRUE, we have just seen the `template' > @@ -6900,6 +6957,14 @@ cp_parser_unqualified_id (cp_parser* parser, > "typedef-name %qD used as destructor declarator", > type_decl); > > + /* "~T...[N]" is a C++26 pack-index-specifier. */ > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > + { > + type_decl = cp_parser_pack_index (parser, type_decl); > + return build_min_nt_loc (loc, BIT_NOT_EXPR, type_decl); > + } > + > return build_min_nt_loc (loc, BIT_NOT_EXPR, TREE_TYPE (type_decl)); > } > > @@ -6970,9 +7035,10 @@ check_template_keyword_in_nested_name_spec (tree name) > class-or-namespace-name :: nested-name-specifier [opt] > class-or-namespace-name :: template nested-name-specifier [opt] > > - nested-name-specifier: [C++0x] > + nested-name-specifier: [C++11] > type-name :: > namespace-name :: > + computed-type-specifier :: > nested-name-specifier identifier :: > nested-name-specifier template [opt] simple-template-id :: > > @@ -7061,8 +7127,8 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, > if (token->type != CPP_NAME) > break; > /* If the following token is neither a `<' (to begin a > - template-id), nor a `::', then we are not looking at a > - nested-name-specifier. */ > + template-id), a `...[' (to begin a pack-index-specifier), > + nor a `::', then we are not looking at a nested-name-specifier. */ > token = cp_lexer_peek_nth_token (parser->lexer, 2); > > if (token->type == CPP_COLON > @@ -7080,6 +7146,10 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, > } > > if (token->type != CPP_SCOPE > + /* See if a pack-index-specifier follows. */ > + && !(token->type == CPP_ELLIPSIS > + && cp_lexer_peek_nth_token (parser->lexer, 3)->type > + == CPP_OPEN_SQUARE) > && !cp_parser_nth_token_starts_template_argument_list_p > (parser, 2)) > break; > @@ -7444,6 +7514,13 @@ cp_parser_qualifying_entity (cp_parser *parser, > is_declaration, > /*enum_ok=*/cxx_dialect > cxx98); > successful_parse_p = only_class_p || cp_parser_parse_definitely (parser); > + > + /* "T...[constant-expression]" is a C++26 pack-index-specifier. */ > + if (successful_parse_p > + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > + scope = cp_parser_pack_index (parser, scope); > + > /* If that didn't work, try for a namespace-name. */ > if (!only_class_p && !successful_parse_p) > { > @@ -17332,6 +17409,12 @@ cp_parser_decltype_expr (cp_parser *parser, > tree id_expression = expr; > cp_id_kind idk; > const char *error_msg; > + const bool pack_index_p > + = (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)); > + const bool have_id_expr_p > + = (pack_index_p > + || cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN); > > if (identifier_p (expr)) > /* Lookup the name we got back from the id-expression. */ > @@ -17343,7 +17426,7 @@ cp_parser_decltype_expr (cp_parser *parser, > && TREE_CODE (expr) != TYPE_DECL > && (TREE_CODE (expr) != BIT_NOT_EXPR > || !TYPE_P (TREE_OPERAND (expr, 0))) > - && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN) > + && have_id_expr_p) > { > /* Complete lookup of the id-expression. */ > expr = (finish_id_expression > @@ -17371,11 +17454,13 @@ cp_parser_decltype_expr (cp_parser *parser, > } > } > > - if (expr > - && expr != error_mark_node > - && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN) > - /* We have an id-expression. */ > - id_expression_or_member_access_p = true; > + if (expr && expr != error_mark_node && have_id_expr_p) > + { > + /* We have an id-expression. */ > + id_expression_or_member_access_p = true; > + if (pack_index_p) > + expr = cp_parser_pack_index (parser, expr); > + } > } > > if (!id_expression_or_member_access_p) > @@ -17938,13 +18023,17 @@ cp_parser_mem_initializer (cp_parser* parser) > /* Parse a mem-initializer-id. > > mem-initializer-id: > - :: [opt] nested-name-specifier [opt] class-name > - decltype-specifier (C++11) > + class-or-decltype > identifier > > + class-or-decltype: > + nested-name-specifier [opt] type-name > + nested-name-specifier template simple-template-id > + computed-type-specifier > + > Returns a TYPE indicating the class to be initialized for the first > - production (and the second in C++11). Returns an IDENTIFIER_NODE > - indicating the data member to be initialized for the last production. */ > + production. Returns an IDENTIFIER_NODE indicating the data member to > + be initialized for the second production. */ > > static tree > cp_parser_mem_initializer_id (cp_parser* parser) > @@ -18015,10 +18104,16 @@ cp_parser_mem_initializer_id (cp_parser* parser) > /*class_head_p=*/false, > /*is_declaration=*/true); > /* If we found one, we're done. */ > - if (cp_parser_parse_definitely (parser)) > - return id; > - /* Otherwise, look for an ordinary identifier. */ > - return cp_parser_identifier (parser); > + if (!cp_parser_parse_definitely (parser)) > + /* Otherwise, look for an ordinary identifier. */ > + id = cp_parser_identifier (parser); > + > + /* ": T...[N]" is a C++26 pack-index-specifier. */ > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > + id = cp_parser_pack_index (parser, id); > + > + return id; > } > > /* Overloading [gram.over] */ > @@ -20436,11 +20531,11 @@ cp_parser_type_specifier (cp_parser* parser, > C++11 Extension: > > simple-type-specifier: > - auto > - decltype ( expression ) > char16_t > char32_t > __underlying_type ( type-id ) > + computed-type-specifier > + placeholder-type-specifier > > C++17 extension: > > @@ -20822,6 +20917,13 @@ cp_parser_simple_type_specifier (cp_parser* parser, > type = NULL_TREE; > } > > + /* "T...[constant-expression]" is a C++26 pack-index-specifier. */ > + if (type > + && type != error_mark_node > + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > + type = cp_parser_pack_index (parser, type); > + > if (!type && flag_concepts && decl_specs) > { > /* Try for a type-constraint with template arguments. We check > @@ -29103,12 +29205,21 @@ cp_parser_base_clause (cp_parser* parser) > /* Parse a base-specifier. > > base-specifier: > - attribute-specifier-seq [opt] :: [opt] nested-name-specifier [opt] > - class-name > - attribute-specifier-seq [opt] virtual access-specifier [opt] :: [opt] > - nested-name-specifier [opt] class-name > - attribute-specifier-seq [opt] access-specifier virtual [opt] :: [opt] > - nested-name-specifier [opt] class-name > + attribute-specifier-seq [opt] class-or-decltype > + attribute-specifier-seq [opt] virtual access-specifier [opt] > + class-or-decltype > + attribute-specifier-seq [opt] access-specifier virtual [opt] > + class-or-decltype > + > + class-or-decltype: > + nested-name-specifier [opt] type-name > + nested-name-specifier template simple-template-id > + computed-type-specifier > + > + access-specifier: > + private > + protected > + public > > Returns a TREE_LIST. The TREE_PURPOSE will be one of > ACCESS_{DEFAULT,PUBLIC,PROTECTED,PRIVATE}_[VIRTUAL]_NODE to > @@ -29237,6 +29348,10 @@ cp_parser_base_specifier (cp_parser* parser) > /*class_head_p=*/false, > /*is_declaration=*/true); > type = TREE_TYPE (type); > + /* ": T...[constant-expression]" is a C++26 pack-index-specifier. */ > + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)) > + type = cp_parser_pack_index (parser, type); > } > > if (type == error_mark_node) > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index f4213f88b99..e7347c0b730 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -1789,6 +1789,11 @@ iterative_hash_template_arg (tree arg, hashval_t val) > val = iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), val); > return iterative_hash_template_arg (PACK_EXPANSION_EXTRA_ARGS (arg), > val); > > + case PACK_INDEX_TYPE: > + case PACK_INDEX_EXPR: > + val = iterative_hash_template_arg (PACK_INDEX_PACK (arg), val); > + return iterative_hash_template_arg (PACK_INDEX_INDEX (arg), val); > + > case TYPE_ARGUMENT_PACK: > case NONTYPE_ARGUMENT_PACK: > return iterative_hash_template_arg (ARGUMENT_PACK_ARGS (arg), val); > @@ -4031,6 +4036,15 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, > void* data) > *walk_subtrees = 0; > return NULL_TREE; > > + case PACK_INDEX_TYPE: > + case PACK_INDEX_EXPR: > + /* We can have an expansion of an expansion, such as "Ts...[Is]...", > + so do look into the index. */ > + cp_walk_tree (&PACK_INDEX_INDEX (t), &find_parameter_packs_r, ppd, > + ppd->visited); > + *walk_subtrees = 0; > + return NULL_TREE; > + > case INTEGER_TYPE: > cp_walk_tree (&TYPE_MAX_VALUE (t), &find_parameter_packs_r, > ppd, ppd->visited); > @@ -4257,6 +4271,33 @@ make_pack_expansion (tree arg, tsubst_flags_t complain) > return result; > } > > +/* Create a PACK_INDEX_* using the pack expansion PACK and index INDEX. */ > + > +tree > +make_pack_index (tree pack, tree index) > +{ > + bool for_types; > + if (TREE_CODE (pack) == TYPE_PACK_EXPANSION) > + for_types = true; > + else if (TREE_CODE (pack) == EXPR_PACK_EXPANSION) > + for_types = false; > + else > + { > + /* Maybe we've already partially substituted the pack. */ > + gcc_checking_assert (TREE_CODE (pack) == TREE_VEC); > + for_types = TYPE_P (TREE_VEC_ELT (pack, 0)); > + } > + > + tree t = (for_types > + ? cxx_make_type (PACK_INDEX_TYPE) > + : make_node (PACK_INDEX_EXPR)); > + PACK_INDEX_PACK (t) = pack; > + PACK_INDEX_INDEX (t) = index; > + if (TREE_CODE (t) == PACK_INDEX_TYPE) > + SET_TYPE_STRUCTURAL_EQUALITY (t); > + return t; > +} > + > /* Checks T for any "bare" parameter packs, which have not yet been > expanded, and issues an error if any are found. This operation can > only be done on full expressions or types (e.g., an expression > @@ -13648,11 +13689,12 @@ add_extra_args (tree extra, tree args, > tsubst_flags_t complain, tree in_decl) > return args; > } > > -/* Substitute ARGS into T, which is an pack expansion > - (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a > +/* Substitute ARGS into T, which is a pack expansion > + (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a > TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node > (if only a partial substitution could be performed) or > ERROR_MARK_NODE if there was an error. */ > + > tree > tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, > tree in_decl) > @@ -13953,6 +13995,26 @@ tsubst_pack_expansion (tree t, tree args, > tsubst_flags_t complain, > return result; > } > > +/* Substitute ARGS into T, which is a pack index (i.e., PACK_INDEX_TYPE or > + PACK_INDEX_EXPR). Returns a single type or expression, a PACK_INDEX_* > + node if only a partial substitution could be performed, or ERROR_MARK_NODE > + if there was an error. */ > + > +tree > +tsubst_pack_index (tree t, tree args, tsubst_flags_t complain, tree in_decl) > +{ > + tree pack = PACK_INDEX_PACK (t); > + if (PACK_EXPANSION_P (pack)) > + pack = tsubst_pack_expansion (pack, args, complain, in_decl); > + tree index = tsubst_expr (PACK_INDEX_INDEX (t), args, complain, in_decl); > + const bool parenthesized_p = (TREE_CODE (t) == PACK_INDEX_EXPR > + && PACK_INDEX_PARENTHESIZED_P (t)); > + if (!value_dependent_expression_p (index) && TREE_CODE (pack) == TREE_VEC) > + return pack_index_element (index, pack, parenthesized_p, complain); > + else > + return make_pack_index (pack, index); > +} > + > /* Make an argument pack out of the TREE_VEC VEC. */ > > static tree > @@ -16341,7 +16403,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, > tree in_decl) > && code != TEMPLATE_PARM_INDEX > && code != IDENTIFIER_NODE > && code != FUNCTION_TYPE > - && code != METHOD_TYPE) > + && code != METHOD_TYPE > + && code != PACK_INDEX_TYPE) > type = tsubst (type, args, complain, in_decl); > if (type == error_mark_node) > return error_mark_node; > @@ -16901,9 +16964,15 @@ tsubst (tree t, tree args, tsubst_flags_t complain, > tree in_decl) > ctx = tsubst_pack_expansion (ctx, args, > complain | tf_qualifying_scope, > in_decl); > - if (ctx == error_mark_node > - || TREE_VEC_LENGTH (ctx) > 1) > + if (ctx == error_mark_node) > return error_mark_node; > + if (TREE_VEC_LENGTH (ctx) > 1) > + { > + if (complain & tf_error) > + error ("%qD expanded to more than one element", > + TYPENAME_TYPE_FULLNAME (t)); > + return error_mark_node; > + } > if (TREE_VEC_LENGTH (ctx) == 0) > { > if (complain & tf_error) > @@ -17078,6 +17147,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, > tree in_decl) > case NONTYPE_ARGUMENT_PACK: > return tsubst_argument_pack (t, args, complain, in_decl); > > + case PACK_INDEX_TYPE: > + return tsubst_pack_index (t, args, complain, in_decl); > + > case VOID_CST: > case INTEGER_CST: > case REAL_CST: > @@ -21779,6 +21851,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t > complain, tree in_decl) > RETURN (r); > } > > + case PACK_INDEX_EXPR: > + RETURN (tsubst_pack_index (t, args, complain, in_decl)); > + > case EXPR_PACK_EXPANSION: > error ("invalid use of pack expansion expression"); > RETURN (error_mark_node); > @@ -28119,8 +28194,9 @@ dependent_type_p_r (tree type) > } > > /* All TYPE_PACK_EXPANSIONs are dependent, because parameter packs must > - be template parameters. */ > - if (TREE_CODE (type) == TYPE_PACK_EXPANSION) > + be template parameters. This includes pack-index-specifiers. */ > + if (TREE_CODE (type) == TYPE_PACK_EXPANSION > + || TREE_CODE (type) == PACK_INDEX_TYPE) > return true; > > if (TREE_CODE (type) == DEPENDENT_OPERATOR_TYPE) > @@ -28743,8 +28819,10 @@ type_dependent_expression_p (tree expression) > && uses_outer_template_parms_in_constraints (expression)) > return true; > > - /* Always dependent, on the number of arguments if nothing else. */ > - if (TREE_CODE (expression) == EXPR_PACK_EXPANSION) > + /* Always dependent, on the number of arguments if nothing else. This > + includes pack-index-expressions. */ > + if (TREE_CODE (expression) == EXPR_PACK_EXPANSION > + || TREE_CODE (expression) == PACK_INDEX_EXPR) > return true; > > if (TREE_TYPE (expression) == unknown_type_node) > diff --git a/gcc/cp/ptree.cc b/gcc/cp/ptree.cc > index 95c7a69e27c..74152c9476d 100644 > --- a/gcc/cp/ptree.cc > +++ b/gcc/cp/ptree.cc > @@ -193,6 +193,11 @@ cxx_print_type (FILE *file, tree node, int indent) > print_node (file, "args", PACK_EXPANSION_EXTRA_ARGS (node), indent + > 4); > return; > > + case PACK_INDEX_TYPE: > + print_node (file, "pack", PACK_INDEX_PACK (node), indent + 4); > + print_node (file, "index", PACK_INDEX_INDEX (node), indent + 4); > + return; > + > default: > return; > } > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index ab8614e376d..6e80717cde7 100644 > --- a/gcc/cp/semantics.cc > +++ b/gcc/cp/semantics.cc > @@ -2453,6 +2453,8 @@ finish_parenthesized_expr (cp_expr expr) > tree stripped_expr = tree_strip_any_location_wrapper (expr); > if (TREE_CODE (stripped_expr) == STRING_CST) > PAREN_STRING_LITERAL_P (stripped_expr) = 1; > + else if (TREE_CODE (stripped_expr) == PACK_INDEX_EXPR) > + PACK_INDEX_PARENTHESIZED_P (stripped_expr) = true; > > expr = cp_expr (force_paren_expr (expr), expr.get_location ()); > > @@ -4848,24 +4850,38 @@ finish_type_pack_element (tree idx, tree types, > tsubst_flags_t complain) > if (TREE_CODE (idx) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (idx))) > { > if (complain & tf_error) > - error ("%<__type_pack_element%> index is not an integral constant"); > + error ("pack index is not an integral constant"); > return error_mark_node; > } > if (tree_int_cst_sgn (idx) < 0) > { > if (complain & tf_error) > - error ("%<__type_pack_element%> index is negative"); > + error ("pack index is negative"); > return error_mark_node; > } > if (wi::to_widest (idx) >= TREE_VEC_LENGTH (types)) > { > if (complain & tf_error) > - error ("%<__type_pack_element%> index is out of range"); > + error ("pack index is out of range"); > return error_mark_node; > } > return TREE_VEC_ELT (types, tree_to_shwi (idx)); > } > > +/* In a pack-index T...[N], return the element at index IDX within TYPES. > + PARENTHESIZED_P is true iff the pack index was wrapped in (). */ > + > +tree > +pack_index_element (tree idx, tree types, bool parenthesized_p, > + tsubst_flags_t complain) > +{ > + tree r = finish_type_pack_element (idx, types, complain); > + if (parenthesized_p) > + /* For the benefit of decltype(auto). */ > + r = force_paren_expr (r); > + return r; > +} > + > /* Implement the __direct_bases keyword: Return the direct base classes > of type. */ > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > index 8e566cadcaf..73c97c35046 100644 > --- a/gcc/cp/tree.cc > +++ b/gcc/cp/tree.cc > @@ -4278,6 +4278,15 @@ cp_tree_equal (tree t1, tree t2) > return false; > return true; > > + case PACK_INDEX_EXPR: > + if (!cp_tree_equal (PACK_INDEX_PACK (t1), > + PACK_INDEX_PACK (t2))) > + return false; > + if (!cp_tree_equal (PACK_INDEX_INDEX (t1), > + PACK_INDEX_INDEX (t2))) > + return false; > + return true; > + > case COMPONENT_REF: > /* If we're comparing contract conditions of overrides, member > references > compare equal if they designate the same member. */ > @@ -5618,6 +5627,13 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, > walk_tree_fn func, > *walk_subtrees_p = 0; > break; > > + case PACK_INDEX_TYPE: > + case PACK_INDEX_EXPR: > + WALK_SUBTREE (PACK_INDEX_PACK (t)); > + WALK_SUBTREE (PACK_INDEX_INDEX (t)); > + *walk_subtrees_p = 0; > + break; > + > case CAST_EXPR: > case REINTERPRET_CAST_EXPR: > case STATIC_CAST_EXPR: > diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc > index 4c15e26f692..50c53dad9c5 100644 > --- a/gcc/cp/typeck.cc > +++ b/gcc/cp/typeck.cc > @@ -1623,6 +1623,12 @@ structural_comptypes (tree t1, tree t2, int strict) > && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1), > PACK_EXPANSION_EXTRA_ARGS (t2))); > > + case PACK_INDEX_TYPE: > + return (cp_tree_equal (PACK_INDEX_PACK (t1), > + PACK_INDEX_PACK (t2)) > + && cp_tree_equal (PACK_INDEX_INDEX (t1), > + PACK_INDEX_INDEX (t2))); > + > case DECLTYPE_TYPE: > if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1) > != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)) > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing1.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing1.C > new file mode 100644 > index 00000000000..e8c7a90ae58 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing1.C > @@ -0,0 +1,102 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++17 } } > +// { dg-options "" } > + > +template<class, class> struct same_type; > +template<class T> struct same_type<T, T> {}; > + > +template<int I, typename... Ts> > +using Type = Ts...[I]; // { dg-warning "pack indexing only available with" > "" { target c++23_down } } > + > +template<int I, auto... Ts> > +constexpr auto Var = Ts...[I]; // { dg-warning "pack indexing only available > with" "" { target c++23_down } } > + > +template <int I, auto...Ts> > +int > +foo () > +{ > + return Ts...[I]; // { dg-warning "pack indexing only available with" "" { > target c++23_down } } > +} > + > +template<typename... Ts> > +struct S { > + Ts...[0] a; // { dg-warning "pack indexing only available with" "" { > target c++23_down } } > +#if __cpp_concepts >= 201907L > + void foo (auto... Vs) { > + decltype(Vs...[1]) d1 = Vs...[1]; // { dg-warning "pack indexing only > available with" "" { target { c++20 && c++23_down } } } > + } > +#endif > +}; > + > +int > +g () > +{ > + using U = Type<1, char, int, float>; > + using U = int; > + > + constexpr auto V = Var<2, 0, 1, 42>; > + static_assert (V == 42); > + > + U r = foo<2, 0, 1, 42>(); > + > + return r; > +} > + > +void > +fn1 () > +{ > + int i = 0; > + [&i](auto... pack) { > + // type is int > + decltype(pack...[0]) x5 = 42; // { dg-warning "pack indexing only > available with" "" { target c++23_down } } > + // type is int& > + [[maybe_unused]] decltype((pack...[0])) x6 = i; // { dg-warning "pack > indexing only available with" "" { target c++23_down } } > + }(0); > +} > + > +#if __cpp_concepts >= 201907L > +int > +bar (auto... pack) > +{ > + (void) pack...[0]; // { dg-warning "pack indexing only available with" "" > { target { c++20 && c++23_down } } } > + int x = pack...[0]; // { dg-warning "pack indexing only available with" "" > { target { c++20 && c++23_down } } } > + return x; > +} > +#endif > + > +template<auto...pack> > +void > +fn2 () > +{ > + [[maybe_unused]] decltype(pack...[0]) x1; // { dg-warning "pack indexing > only available with" "" { target c++23_down } } > + [[maybe_unused]] decltype((pack...[0])) x2; // { dg-warning "pack indexing > only available with" "" { target c++23_down } } > + same_type<decltype(x1), int>(); > + same_type<decltype(x2), int>(); > +} > + > +template<typename... T> > +void > +fn3 (int p) > +{ > + T...[0] a = p; // { dg-warning "pack indexing only available with" "" { > target c++23_down } } > + (T...[0])(a); // { dg-warning "pack indexing only available with" "" { > target c++23_down } } > +} > + > +template<int... Is> > +void fn4 () > +{ > + same_type<decltype(Is...[0]), int>(); // { dg-warning "pack indexing > only available with" "" { target c++23_down } } > + same_type<decltype((Is...[0])), int>(); // { dg-warning "pack indexing > only available with" "" { target c++23_down } } > +} > + > +void > +g3 () > +{ > + fn2<0>(); > +#if __cpp_concepts >= 201907L > + bar (0); > +#endif > + S<int> s; > + fn4<0, 1, 2>(); > +} > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing10.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing10.C > new file mode 100644 > index 00000000000..3cd348b3ec6 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing10.C > @@ -0,0 +1,15 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > + > +template<auto... Vs> > +constexpr auto f() { > + return []<int N>() { return Vs...[N]; }.template operator()<1>(); > +} > +static_assert(f<1, 2, 3>() == 2); > + > +template<int N> > +constexpr auto g() { > + return []<auto... Vs>() { return Vs...[N]; }.template operator()<1, 2, > 3>(); > +} > +static_assert(g<1>() == 2); > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing11.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing11.C > new file mode 100644 > index 00000000000..81e4da8603a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing11.C > @@ -0,0 +1,13 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > +// Test case from [diff.cpp23.dcl.dcl]. > + > +template <typename... T> > +void f(T... [1]); > +template <typename... T> > +void g(T... ptr[1]); > +int main() { > + f<int, double>(nullptr, nullptr); // { dg-error "no matching function" > } > + g<int, double>(nullptr, nullptr); // ok > +} > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C > new file mode 100644 > index 00000000000..ec32527ed80 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing2.C > @@ -0,0 +1,111 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > +// Test invalid cases. > + > +template<int I, typename... Ts> > +using Type = Typo...[I]; // { dg-error "does not name a type" } > + > +template<int I, auto... Ts> > +constexpr auto Var = Typo...[I]; // { dg-error "no parameter packs" } > + > +template<typename... Ts> > +void foo(Ts...[]); // { dg-error "pack index missing" } > + > +template <typename... Ts> > +void f(Ts...[1]); > + > +template<int... N> > +int f2 (X... [N]); // { dg-error "contains no parameter packs" } > + > +struct X; > + > +template<typename T> > +struct TX; > + > +template <typename T, auto V, template<typename> typename Tp> > +void > +bad (int i) > +{ > + i...[0]; // { dg-error "no parameter packs" } > + V...[0]; // { dg-error "no parameter packs" } > + X...[0] x; // { dg-error "no parameter packs" } > + T...[0] t; // { dg-error "no parameter packs" } > + Tp...[0] tp; // { dg-error "expected" } > + > + X...[0] xarr[1]; // { dg-error "no parameter packs" } > + T...[0] tarr[1]; // { dg-error "no parameter packs" } > + Tp...[0] tparr[1]; // { dg-error "expected" } > +} > + > +template<int N> > +int > +getT (auto... Ts) > +{ > + return Ts...[N]; // { dg-error "pack index is out of range" } > +} > + > +template<int N> > +int > +getT2 (auto... Ts) > +{ > + return Ts...[N]; // { dg-error "pack index is negative" } > +} > + > +template<auto N, typename... Ts> > +void > +badtype () > +{ > + Ts...[N] t; // { dg-error "pack index is out of range" } > +} > + > +template<auto N, typename... Ts> > +void > +badtype2 () > +{ > + Ts...[N] t; // { dg-error "pack index is negative" } > +} > + > +int nonconst () { return 42; } > + > +template<typename... Ts> > +void > +badindex () > +{ > + Ts...[nonconst ()] t; // { dg-error "pack index is not an integral > constant" } > + // { dg-error "non-.constexpr. function" "" { target *-*-* } .-1 } > +} > + > +template<typename... Ts> > +struct broken { > + Ts...1; // { dg-error "expected" } > + Ts...[; // { dg-error "invalid" } > + Ts...[1; // { dg-error "invalid" } > + Ts...[]; // { dg-error "pack index missing" } > + > + void foo (auto...Vs) { > + decltype(Vs...[1]) d1 = Vs...[]; // { dg-error "pack index missing" } > + decltype(Vs...[1]) d2 = Vs...[; // { dg-error "expected" } > + } > +}; > + > +int main() > +{ > + // void f<int, double>(int [1], double [1]) > + f<int, double>(nullptr, nullptr); // { dg-error "no matching function" } > + bad<int, 0, TX>(42); > + > + getT<0>(); // { dg-message "required from here" } > + getT<1>(); // { dg-message "required from here" } > + getT2<-1>(); // { dg-message "required from here" } > + > + badtype<0>(); // { dg-message "required from here" } > + badtype<1, int>(); // { dg-message "required from here" } > + badtype2<-1>(); // { dg-message "required from here" } > + badtype2<-1, int>(); // { dg-message "required from here" } > + > + badindex<int, int, int>(); > + > + bool b = nothere...[0]; // { dg-error "no parameter packs" } > + using E = nothere...[0]; // { dg-error "does not name a type" } > +} > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing3.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing3.C > new file mode 100644 > index 00000000000..8c10b307f3a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing3.C > @@ -0,0 +1,41 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > +// From LLVM's cxx2c-pack-indexing.cpp. > + > +template<typename...> > +struct X { }; > + > +template<typename... T> > +requires requires(T...[0]) { {T...[0](0)}; } > +struct S : T...[1] { > + [[maybe_unused]] T...[1] base = {}; > + using foo = T...[1]; > + S() : T...[1]() { } > + X<T...[0]> x; > + const T...[0] f(T...[0]&& parm) noexcept((T...[0])0) { > + T...[0] (*test)(const volatile T...[0]**); > + thread_local T...[0] d; > + [[maybe_unused]] T...[0] a = parm; > + auto ptr = new T...[0](0); > + (*ptr).~T...[0](); > + return T...[0](0); > + typename T...[1]::foo b = 0; > + T...[1]::i = 0; > + return (T...[0])(a); > + new T...[0]; > + [[maybe_unused]] auto l = []<T...[0]>(T...[0][1]) -> T...[0]{ return {}; > }; > + [[maybe_unused]] auto _ = l.template operator()<T...[0]{}>({0}); > + } > + operator T...[0]() const { } > +}; > + > +struct base { > + using foo = int; > + static inline int i = 42; > +}; > + > +int main() > +{ > + S<int, base>().f(0); > +} > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing4.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing4.C > new file mode 100644 > index 00000000000..8decf3064bc > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing4.C > @@ -0,0 +1,65 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > +// From LLVM's cxx2c-pack-indexing.cpp. > + > +template <class, class> > +constexpr bool is_same = false; > +template <class T> > +constexpr bool is_same<T, T> = true; > + > +template <typename T> > +constexpr bool > +f (auto&&... p) > +{ > + return is_same<T, decltype(p...[0])>; > +} > + > +void > +g () > +{ > + int a = 0; > + const int b = 0; > + static_assert(f<int&&>(0)); > + static_assert(f<int&>(a)); > + static_assert(f<const int&>(b)); > +} > + > +template<auto... p> > +struct A { > + enum E { > + x = p...[0] > + }; > +}; > +static_assert(A<42>::x == 42); > + > +struct S { }; > +template<auto... p> > +constexpr auto constant_initializer = p...[0]; > +constexpr auto InitOk = constant_initializer<S{}>; > + > +consteval int evaluate(auto... p) { > + return p...[0]; > +} > +constexpr int x = evaluate(42, S{}); > +static_assert(x == 42); > + > +template <auto... Is> > +struct IL{}; > + > +template <typename... Ts> > +struct TL{}; > + > +template <typename Tl, typename Il> > +struct SpliceImpl; > + > +template <typename... Ts, auto... Is> > +struct SpliceImpl<TL<Ts...>, IL<Is...>> > +{ > + using type = TL<Ts...[Is]...>; > +}; > + > +template <typename Tl, typename Il> > +using Splice = typename SpliceImpl<Tl, Il>::type; > +using type = Splice<TL<char, short, long, double>, IL<1, 2>>; > +static_assert(is_same<type, TL<short, long>>); > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing5.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing5.C > new file mode 100644 > index 00000000000..901956e2dae > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing5.C > @@ -0,0 +1,41 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > + > +template<class, class> struct same_type; > +template<class T> struct same_type<T, T> {}; > + > +void > +fn1 (auto... Ts) > +{ > + same_type<decltype(Ts...[0]), int>(); > + same_type<decltype((Ts...[0])), int&>(); > + same_type<decltype(Ts...[1]), unsigned int>(); > + same_type<decltype((Ts...[1])), unsigned int&>(); > +} > + > +template<auto... Is> > +void > +fn2 () > +{ > + same_type<decltype(Is...[0]), int>(); > + same_type<decltype((Is...[0])), int>(); > + same_type<decltype(Is...[1]), unsigned int>(); > + same_type<decltype((Is...[1])), unsigned int>(); > + same_type<decltype(Is...[2]), double>(); > + same_type<decltype((Is...[2])), double>(); > + same_type<decltype(Is...[3]), float>(); > + same_type<decltype((Is...[3])), float>(); > + same_type<decltype(Is...[4]), unsigned char>(); > + same_type<decltype((Is...[4])), unsigned char>(); > +} > + > +static constexpr unsigned char c = 'A'; > + > +void > +g () > +{ > + int i = 42; > + fn1 (i, 42u); > + fn2<0, 1u, 2.0, 3.f, c>(); > +} > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing6.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing6.C > new file mode 100644 > index 00000000000..9af88765254 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing6.C > @@ -0,0 +1,51 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > + > +template<class, class> struct same_type; > +template<class T> struct same_type<T, T> {}; > + > +void > +fn1 (auto... Ts) > +{ > + decltype(auto) a1 = Ts...[0]; > + same_type<decltype(a1), int>(); > + decltype(auto) a2 = (Ts...[0]); > + same_type<decltype(a2), int&>(); > +} > + > +template<auto... Is> > +void > +fn2 () > +{ > + decltype(auto) a1 = Is...[0]; > + same_type<decltype(a1), int>(); > + decltype(auto) a2 = (Is...[0]); > + same_type<decltype(a2), int>(); > + decltype(auto) a3 = Is...[1]; > + same_type<decltype(a3), unsigned int>(); > + decltype(auto) a4 = (Is...[1]); > + same_type<decltype(a4), unsigned int>(); > + decltype(auto) a5 = Is...[2]; > + same_type<decltype(a5), double>(); > + decltype(auto) a6 = (Is...[2]); > + same_type<decltype(a6), double>(); > + decltype(auto) a7 = Is...[3]; > + same_type<decltype(a7), float>(); > + decltype(auto) a8 = (Is...[3]); > + same_type<decltype(a8), float>(); > + decltype(auto) a9 = Is...[4]; > + same_type<decltype(a9), unsigned char>(); > + decltype(auto) a10 = (Is...[4]); > + same_type<decltype(a10), unsigned char>(); > +} > + > +static constexpr unsigned char c = 'A'; > + > +void > +g () > +{ > + int i = 42; > + fn1 (i, 42u); > + fn2<0, 1u, 2.0, 3.f, c>(); > +} > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing7.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing7.C > new file mode 100644 > index 00000000000..de50f7758e3 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing7.C > @@ -0,0 +1,16 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > + > +template <int I, auto...Ts> > +decltype(Ts...[I]) > +foo () // { dg-bogus "sorry, unimplemented: > mangling" "" { xfail *-*-* } } > +{ > + return Ts...[I]; > +} > + > +int > +g () > +{ > + return foo<2, 0, 1, 42>(); > +} > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing8.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing8.C > new file mode 100644 > index 00000000000..2b1b67c0841 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing8.C > @@ -0,0 +1,23 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do run { target c++26 } } > + > +#include <initializer_list> > + > +template<typename... Ts> > +int > +g (auto... Is) > +{ > + std::initializer_list<Ts...[0]> l{ Is...[0], Is...[1], Is...[2], Is...[3], > Is...[4] }; > + int sum = 0; > + for (auto x : l) > + sum += x; > + return sum; > +} > + > +int > +main () > +{ > + if (g<int> (1, 2, 3, 4, 5) != 15) > + __builtin_abort (); > +} > diff --git a/gcc/testsuite/g++.dg/cpp26/pack-indexing9.C > b/gcc/testsuite/g++.dg/cpp26/pack-indexing9.C > new file mode 100644 > index 00000000000..afd8a2f9ed6 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp26/pack-indexing9.C > @@ -0,0 +1,27 @@ > +// P2662R3 - Pack Indexing > +// PR c++/113798 > +// { dg-do compile { target c++26 } } > +// From <https://github.com/itanium-cxx-abi/cxx-abi/issues/175>. > + > +template <class... T> struct tuple { > + template <unsigned I> T...[I] get(); // { dg-bogus "sorry, unimplemented: > mangling" "" { xfail *-*-* } } > +}; > + > +int > +g () > +{ > + tuple<int> t; > + return t.get<0>(); > +} > + > +template<typename T, typename U> concept C = true; > +template<typename ...T> struct A { > + template<int I, typename ...U> void f(T...[I], U...[I]) requires > C<T...[I], U...[I]>; // { dg-message "sorry, unimplemented: mangling" } > +}; > + > +void > +h () > +{ > + A<char, int, double> a; > + a.f<1, int, int, char>(1, 2); > +} > diff --git a/gcc/testsuite/g++.dg/modules/pack-index-1_a.C > b/gcc/testsuite/g++.dg/modules/pack-index-1_a.C > new file mode 100644 > index 00000000000..30ae189711c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/pack-index-1_a.C > @@ -0,0 +1,18 @@ > +// { dg-module-do run } > +// { dg-additional-options { -std=c++26 -fmodules-ts } } > + > +export module packing1; > +// { dg-module-cmi "packing1" } > + > +export template<int I, typename... Ts> > +using Type = Ts...[I]; > + > +export template<int I, auto... Ts> > +constexpr auto Var = Ts...[I]; > + > +export template <int I, auto...Ts> > +int > +foo () > +{ > + return Ts...[I]; > +} > diff --git a/gcc/testsuite/g++.dg/modules/pack-index-1_b.C > b/gcc/testsuite/g++.dg/modules/pack-index-1_b.C > new file mode 100644 > index 00000000000..dce6f5774d3 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/pack-index-1_b.C > @@ -0,0 +1,15 @@ > +// { dg-additional-options { -std=c++26 -fmodules-ts } } > + > +import packing1; > + > +int > +main () > +{ > + using U = Type<1, char, int, float>; > + using U = int; > + > + U r = foo<2, 0, 1, 42>(); > + > + constexpr auto V = Var<2, 0, 1, 42>; > + static_assert (V == 42); > +} > diff --git a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc > b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc > index 2346c29b80f..9e002f4d47a 100644 > --- a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc > +++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc > @@ -61,4 +61,4 @@ test03() > > // { dg-error "tuple index must be in range" "" { target *-*-* } 0 } > // { dg-prune-output "no type named 'type' in .*_Nth_type" } > -// { dg-prune-output "'__type_pack_element' index is out of range" } > +// { dg-prune-output "pack index is out of range" } > > base-commit: 345eb9b795d9728733bd0e472529e259ce796ff6 > -- > 2.47.0 >
Marek