c++: Implement P2662R3, Pack Indexing [PR113798]
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_next_tokens_are_pack_index_p): New. (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): Recurse on PACK_INDEX_PACK 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.
This commit is contained in:
parent
c5126f0a00
commit
c435272166
28 changed files with 910 additions and 38 deletions
|
@ -9943,6 +9943,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);
|
||||
|
|
|
@ -645,6 +645,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);
|
||||
|
@ -702,6 +703,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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -7582,6 +7608,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);
|
||||
|
@ -7907,6 +7934,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);
|
||||
|
|
|
@ -1219,6 +1219,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;
|
||||
|
@ -1919,6 +1926,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);
|
||||
|
|
|
@ -813,6 +813,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;
|
||||
|
@ -1087,6 +1094,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;
|
||||
|
@ -1219,6 +1227,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:
|
||||
|
@ -3102,6 +3111,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:
|
||||
|
|
|
@ -2668,6 +2668,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. */
|
||||
|
||||
|
|
|
@ -9273,6 +9273,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));
|
||||
|
@ -9840,6 +9845,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 ();
|
||||
|
|
167
gcc/cp/parser.cc
167
gcc/cp/parser.cc
|
@ -5740,6 +5740,62 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1)
|
|||
return finish_binary_fold_expr (loc, expr1, expr2, op);
|
||||
}
|
||||
|
||||
/* Return true iff the next tokens (following a typedef-name or id-expression)
|
||||
start a pack index. */
|
||||
|
||||
static bool
|
||||
cp_parser_next_tokens_are_pack_index_p (cp_parser *parser)
|
||||
{
|
||||
return (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
|
||||
&& cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE));
|
||||
}
|
||||
|
||||
/* 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);
|
||||
return make_pack_index (pack, index);
|
||||
}
|
||||
|
||||
/* Parse a primary-expression.
|
||||
|
||||
primary-expression:
|
||||
|
@ -6369,6 +6425,11 @@ 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_parser_next_tokens_are_pack_index_p (parser))
|
||||
decl = cp_parser_pack_index (parser, decl);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
|
@ -6412,6 +6473,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
|
||||
|
@ -6594,7 +6656,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'
|
||||
|
@ -6901,6 +6965,13 @@ 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_parser_next_tokens_are_pack_index_p (parser))
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -6971,9 +7042,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 ::
|
||||
|
||||
|
@ -7062,8 +7134,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
|
||||
|
@ -7081,6 +7153,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;
|
||||
|
@ -7445,6 +7521,12 @@ 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_parser_next_tokens_are_pack_index_p (parser))
|
||||
scope = cp_parser_pack_index (parser, scope);
|
||||
|
||||
/* If that didn't work, try for a namespace-name. */
|
||||
if (!only_class_p && !successful_parse_p)
|
||||
{
|
||||
|
@ -17368,6 +17450,10 @@ 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_parser_next_tokens_are_pack_index_p (parser);
|
||||
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. */
|
||||
|
@ -17379,7 +17465,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
|
||||
|
@ -17407,11 +17493,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)
|
||||
|
@ -17974,13 +18062,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)
|
||||
|
@ -18051,10 +18143,15 @@ 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_parser_next_tokens_are_pack_index_p (parser))
|
||||
id = cp_parser_pack_index (parser, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/* Overloading [gram.over] */
|
||||
|
@ -20472,11 +20569,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:
|
||||
|
||||
|
@ -20858,6 +20955,12 @@ 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_parser_next_tokens_are_pack_index_p (parser))
|
||||
type = cp_parser_pack_index (parser, type);
|
||||
|
||||
if (!type && flag_concepts && decl_specs)
|
||||
{
|
||||
/* Try for a type-constraint with template arguments. We check
|
||||
|
@ -29139,12 +29242,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
|
||||
|
@ -29273,6 +29385,9 @@ 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_parser_next_tokens_are_pack_index_p (parser))
|
||||
type = cp_parser_pack_index (parser, type);
|
||||
}
|
||||
|
||||
if (type == error_mark_node)
|
||||
|
|
98
gcc/cp/pt.cc
98
gcc/cp/pt.cc
|
@ -1788,6 +1788,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);
|
||||
|
@ -4030,6 +4035,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 (but not the pack). */
|
||||
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);
|
||||
|
@ -4256,6 +4270,36 @@ 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)
|
||||
{
|
||||
if (pack == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
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
|
||||
|
@ -13647,11 +13691,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)
|
||||
|
@ -13952,6 +13997,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
|
||||
|
@ -16340,7 +16405,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;
|
||||
|
@ -16900,9 +16966,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)
|
||||
|
@ -17077,6 +17149,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:
|
||||
|
@ -21869,6 +21944,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);
|
||||
|
@ -28209,8 +28287,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)
|
||||
|
@ -28837,6 +28916,11 @@ type_dependent_expression_p (tree expression)
|
|||
if (TREE_CODE (expression) == EXPR_PACK_EXPANSION)
|
||||
return true;
|
||||
|
||||
/* [temp.dep.expr]: "A pack-index-expression is type-dependent if its
|
||||
id-expression is type-dependent." */
|
||||
if (TREE_CODE (expression) == PACK_INDEX_EXPR)
|
||||
return type_dependent_expression_p (PACK_INDEX_PACK (expression));
|
||||
|
||||
if (TREE_TYPE (expression) == unknown_type_node)
|
||||
{
|
||||
if (TREE_CODE (expression) == ADDR_EXPR)
|
||||
|
|
|
@ -192,6 +192,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;
|
||||
}
|
||||
|
|
|
@ -2452,6 +2452,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. */
|
||||
|
||||
|
|
|
@ -4277,6 +4277,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. */
|
||||
|
@ -5617,6 +5626,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:
|
||||
|
|
|
@ -1622,6 +1622,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))
|
||||
|
|
102
gcc/testsuite/g++.dg/cpp26/pack-indexing1.C
Normal file
102
gcc/testsuite/g++.dg/cpp26/pack-indexing1.C
Normal file
|
@ -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>();
|
||||
}
|
15
gcc/testsuite/g++.dg/cpp26/pack-indexing10.C
Normal file
15
gcc/testsuite/g++.dg/cpp26/pack-indexing10.C
Normal file
|
@ -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);
|
13
gcc/testsuite/g++.dg/cpp26/pack-indexing11.C
Normal file
13
gcc/testsuite/g++.dg/cpp26/pack-indexing11.C
Normal file
|
@ -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
|
||||
}
|
111
gcc/testsuite/g++.dg/cpp26/pack-indexing2.C
Normal file
111
gcc/testsuite/g++.dg/cpp26/pack-indexing2.C
Normal file
|
@ -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" }
|
||||
}
|
41
gcc/testsuite/g++.dg/cpp26/pack-indexing3.C
Normal file
41
gcc/testsuite/g++.dg/cpp26/pack-indexing3.C
Normal file
|
@ -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);
|
||||
}
|
65
gcc/testsuite/g++.dg/cpp26/pack-indexing4.C
Normal file
65
gcc/testsuite/g++.dg/cpp26/pack-indexing4.C
Normal file
|
@ -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>>);
|
41
gcc/testsuite/g++.dg/cpp26/pack-indexing5.C
Normal file
41
gcc/testsuite/g++.dg/cpp26/pack-indexing5.C
Normal file
|
@ -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>();
|
||||
}
|
51
gcc/testsuite/g++.dg/cpp26/pack-indexing6.C
Normal file
51
gcc/testsuite/g++.dg/cpp26/pack-indexing6.C
Normal file
|
@ -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>();
|
||||
}
|
16
gcc/testsuite/g++.dg/cpp26/pack-indexing7.C
Normal file
16
gcc/testsuite/g++.dg/cpp26/pack-indexing7.C
Normal file
|
@ -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>();
|
||||
}
|
23
gcc/testsuite/g++.dg/cpp26/pack-indexing8.C
Normal file
23
gcc/testsuite/g++.dg/cpp26/pack-indexing8.C
Normal file
|
@ -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 ();
|
||||
}
|
27
gcc/testsuite/g++.dg/cpp26/pack-indexing9.C
Normal file
27
gcc/testsuite/g++.dg/cpp26/pack-indexing9.C
Normal file
|
@ -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);
|
||||
}
|
18
gcc/testsuite/g++.dg/modules/pack-index-1_a.C
Normal file
18
gcc/testsuite/g++.dg/modules/pack-index-1_a.C
Normal file
|
@ -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];
|
||||
}
|
15
gcc/testsuite/g++.dg/modules/pack-index-1_b.C
Normal file
15
gcc/testsuite/g++.dg/modules/pack-index-1_b.C
Normal file
|
@ -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);
|
||||
}
|
|
@ -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" }
|
||||
|
|
Loading…
Add table
Reference in a new issue