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);
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);
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);
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.
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.
|| 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
#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) \
? &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))
#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)
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);
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);
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;
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);
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;
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;
case TYPE_PACK_EXPANSION:
case FIXED_POINT_TYPE:
case NULLPTR_TYPE:
+ case PACK_INDEX_TYPE:
break;
default:
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:
"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. */
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));
}
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 ();
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:
= 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;
}
id-expression:
unqualified-id
qualified-id
+ pack-index-expression
qualified-id:
:: [opt] nested-name-specifier template [opt] unqualified-id
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'
"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));
}
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 ::
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
}
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;
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)
{
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. */
&& 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
}
}
- 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)
/* 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)
/*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] */
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:
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
/* 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
/*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)
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);
*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);
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
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)
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
&& 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;
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)
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:
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);
}
/* 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)
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)
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;
}
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 ());
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. */
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. */
*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:
&& 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))
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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);
--- /dev/null
+// 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
+}
--- /dev/null
+// 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" }
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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>>);
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+// { 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];
+}
--- /dev/null
+// { 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);
+}
// { 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" }