On 11/6/24 3:33 PM, 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:
+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.
I guess the question is whether we need to deal with the vexing parse.
But in this case it'd be ill-formed regardless, so what you have is fine.
@@ -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.
Ah, makes sense.
+ ~ computed-type-specifier
Hmm, seems we never implemented ~decltype.
Looks like CWG 1753: <https://gcc.gnu.org/PR117450>.
Thanks.
@@ -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.
Makes sense.
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?
No. Really, given that we're reusing this grammar, it's probably fine
to never fix it.
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.
+ MARK_TS_TYPE_NON_COMMON (PACK_INDEX_TYPE);
I wonder about trying to use the tree_common symtab member for the type
index so we don't need non_common, but that's not necessary.
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE))
This happens a lot in the parser changes, how about factoring it into
cp_parser_next_tokens_are_pack_index?
Or change cp_parser_pack_index to cp_parser_maybe_pack_index that does
this check, then returns the argument if we aren't looking at a pack index?
+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;
Let's move the error handling into make_pack_index.
@@ -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. */
Let's add "...but not the pack."
@@ -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;
Actually I don't think this includes pack-index-expressions; for them,
you always get one result.
https://eel.is/c++draft/temp#dep.expr-8 says it's type-dependent if the
pack is type-dependent.
Jason