diff options
author | Patrick Palka <ppalka@redhat.com> | 2022-12-15 18:50:16 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2022-12-15 18:50:16 -0500 |
commit | e79d51963378b10ab90544a7d8eeb6266e9a57f6 (patch) | |
tree | 268e1db420be13769feae29da9fe3a4dcbf2f7a0 /gcc/cp/pt.cc | |
parent | 57ab3714b6c436032ca440f9432c5837928de969 (diff) | |
download | gcc-e79d51963378b10ab90544a7d8eeb6266e9a57f6.zip gcc-e79d51963378b10ab90544a7d8eeb6266e9a57f6.tar.gz gcc-e79d51963378b10ab90544a7d8eeb6266e9a57f6.tar.bz2 |
c++: variadic using-decl with parm pack in terminal name [PR102104]
There's a curious corner case with variadic member using-decls: the
terminal name can also contain a parameter pack, and only through naming
a conversion function, e.g.
using A<Ts>::operator Ts...;
We currently only handle parameter packs appearing in the qualifying
scope of a variadic using-decl; this patch adds support for the above
case as well, representing such a using-decl via two pack expansions,
one for the qualifying scope and one for the terminal name (despite
logically there being just one). Then at instantiation time we manually
merge them.
PR c++/102104
PR c++/108090
gcc/cp/ChangeLog:
* error.cc (dump_decl) <case USING_DECL>: Look through a
pack expansion in the name as well.
* parser.cc (cp_parser_using_declaration): Handle a parameter
pack appearing in the terminal name of a variadic using-decl.
* pt.cc (tsubst_decl) <case USING_DECL>: Likewise. Combine the
handling of variadic and non-variadic using-decls.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1z/using-variadic1.C: New test.
* g++.dg/cpp1z/using-variadic1a.C: New test.
* g++.dg/cpp1z/using-variadic1b.C: New test.
* g++.dg/cpp1z/using-variadic1c.C: New test.
* g++.dg/cpp1z/using-variadic2.C: New test.
* g++.dg/cpp1z/using-variadic3.C: New test.
Diffstat (limited to 'gcc/cp/pt.cc')
-rw-r--r-- | gcc/cp/pt.cc | 90 |
1 files changed, 64 insertions, 26 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index b9933ec..bc566ab 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -14962,43 +14962,81 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (DECL_DEPENDENT_P (t) || uses_template_parms (USING_DECL_SCOPE (t))) { + /* True iff this using-decl was written as a pack expansion + (and a pack appeared in its scope or name). If a pack + appeared in both, we expand the packs separately and + manually merge them. */ + bool variadic_p = false; + tree scope = USING_DECL_SCOPE (t); - tree name = tsubst_copy (DECL_NAME (t), args, complain, in_decl); if (PACK_EXPANSION_P (scope)) { - tree vec = tsubst_pack_expansion (scope, args, complain, in_decl); - int len = TREE_VEC_LENGTH (vec); - r = make_tree_vec (len); - for (int i = 0; i < len; ++i) + scope = tsubst_pack_expansion (scope, args, complain, in_decl); + variadic_p = true; + } + else + scope = tsubst_copy (scope, args, complain, in_decl); + + tree name = DECL_NAME (t); + if (IDENTIFIER_CONV_OP_P (name) + && PACK_EXPANSION_P (TREE_TYPE (name))) + { + name = tsubst_pack_expansion (TREE_TYPE (name), args, + complain, in_decl); + if (name == error_mark_node) { - tree escope = TREE_VEC_ELT (vec, i); - tree elt = do_class_using_decl (escope, name); - if (!elt) - { - r = error_mark_node; - break; - } - else - { - TREE_PROTECTED (elt) = TREE_PROTECTED (t); - TREE_PRIVATE (elt) = TREE_PRIVATE (t); - } - TREE_VEC_ELT (r, i) = elt; + r = error_mark_node; + break; } + for (tree& elt : tree_vec_range (name)) + elt = make_conv_op_name (elt); + variadic_p = true; } else + name = tsubst_copy (name, args, complain, in_decl); + + int len; + if (!variadic_p) + len = 1; + else if (TREE_CODE (scope) == TREE_VEC + && TREE_CODE (name) == TREE_VEC) { - tree inst_scope = tsubst_copy (USING_DECL_SCOPE (t), args, - complain, in_decl); - r = do_class_using_decl (inst_scope, name); - if (!r) - r = error_mark_node; - else + if (TREE_VEC_LENGTH (scope) != TREE_VEC_LENGTH (name)) { - TREE_PROTECTED (r) = TREE_PROTECTED (t); - TREE_PRIVATE (r) = TREE_PRIVATE (t); + error ("mismatched argument pack lengths (%d vs %d)", + TREE_VEC_LENGTH (scope), TREE_VEC_LENGTH (name)); + r = error_mark_node; + break; } + len = TREE_VEC_LENGTH (scope); } + else if (TREE_CODE (scope) == TREE_VEC) + len = TREE_VEC_LENGTH (scope); + else /* TREE_CODE (name) == TREE_VEC */ + len = TREE_VEC_LENGTH (name); + + r = make_tree_vec (len); + for (int i = 0; i < len; ++i) + { + tree escope = (TREE_CODE (scope) == TREE_VEC + ? TREE_VEC_ELT (scope, i) + : scope); + tree ename = (TREE_CODE (name) == TREE_VEC + ? TREE_VEC_ELT (name, i) + : name); + tree elt = do_class_using_decl (escope, ename); + if (!elt) + { + r = error_mark_node; + break; + } + TREE_PROTECTED (elt) = TREE_PROTECTED (t); + TREE_PRIVATE (elt) = TREE_PRIVATE (t); + TREE_VEC_ELT (r, i) = elt; + } + + if (!variadic_p && r != error_mark_node) + r = TREE_VEC_ELT (r, 0); } else { |