Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mangling for C++ pack indexing #175

Open
cor3ntin opened this issue Jan 10, 2024 · 4 comments
Open

Mangling for C++ pack indexing #175

cor3ntin opened this issue Jan 10, 2024 · 4 comments

Comments

@cor3ntin
Copy link

Hey folks

Pack indexing (https://wg21.link/p2662r3) was approved for C++26.
We will need to mangle these things.

A pack indexing is constituted of a pattern (which is either a type or an expression) and an indexing expression.
I am unfortunately not familiar enough with the ABI to offer suggestions

@rjmccall
Copy link
Collaborator

rjmccall commented Jan 11, 2024

Looks like it's a new type-level operator and a new expression-level operator. Apparently it will eventually be accepted as a template-name as well, but that's not currently included? Anyway, this should be straightforward; we just need to add new forms to <expression> and <type>.

Typical uses of this are probably going to exacerbate our existing problems with partial substitution, though. Consider when a pack indexing operator is used in the signature of a templated member of a class template and we can't expand the pack in the instantiated dependent signature of the template:

template <class... T> struct tuple {
  template <unsigned I> T...[I] get();
};

We'll need to solve that problem.

@cor3ntin
Copy link
Author

Ping on that, it would be nice to settle on a grammar! Thanks

@jicama
Copy link
Contributor

jicama commented Oct 25, 2024

template <class... T> struct tuple {
  template <unsigned I> T...[I] get();
};

I would expect mangling of T...[I] to just refer to the two template parameters, following the mangling for template parameters at different depths from PR #85 .

@zygoloid
Copy link
Contributor

I agree that using a reference to a template parameter by depth and index makes sense here. The scheme in #85 counts levels inwards from the first non-substituted level, and so L in this case would be -1, for which we don't yet have a mangling. Maybe something like TM<1 - L>_<index - 1>_, so I in the previous example would be TM0__?

One additional thought on this:

The "count from the first non-substituted level" rule means that we get different template parameter numbering in constraints versus the rest of the signature (due to the different number of substituted levels), which is annoying for demanglers to deal with. It'd be nice to change that to also use this new negative-levels numbering relative to the total number of substituted levels for the <encoding>, so that in

template<typename T, typename U> concept C = true;
template<typename ...T> struct A {
    template<typename ...U, int I> void f(T...[I], U...[I]) requires C<T...[I], U...[I]>;
};

... we'd use TM0__ and T_ to refer to T and U in both the constraint and the parameter types, rather than instead using T_ and TL0__ for T and U in the constraint as we currently do. Obviously that's an ABI break, and maybe it's already too late, but I think it would be a substantial improvement to the ease of demangling.

hubot pushed a commit to gcc-mirror/gcc that referenced this issue Nov 28, 2024
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 <itanium-cxx-abi/cxx-abi#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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants