Message ID | 20221215161535.2731182-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: variadic using-decl with parm pack in terminal name [PR102104] | expand |
On 12/15/22 11:15, Patrick Palka wrote: > 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 with 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. > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk? OK. > 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.c (cp_parser_using_declaration): Handle a parameter > pack appearing in the terminal name of a variadic using-decl. > * pt.c (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. > --- > gcc/cp/error.cc | 9 ++ > gcc/cp/parser.cc | 33 ++++++- > gcc/cp/pt.cc | 91 ++++++++++++++----- > gcc/testsuite/g++.dg/cpp1z/using-variadic1.C | 29 ++++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C | 34 +++++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C | 37 ++++++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C | 33 +++++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic2.C | 24 +++++ > gcc/testsuite/g++.dg/cpp1z/using-variadic3.C | 8 ++ > 9 files changed, 272 insertions(+), 26 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic1.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic2.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/using-variadic3.C > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc > index 12b28e8ee5b..e7f60335cc0 100644 > --- a/gcc/cp/error.cc > +++ b/gcc/cp/error.cc > @@ -1477,11 +1477,20 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) > if (!(flags & TFF_UNQUALIFIED_NAME)) > { > tree scope = USING_DECL_SCOPE (t); > + tree name = DECL_NAME (t); > if (PACK_EXPANSION_P (scope)) > { > scope = PACK_EXPANSION_PATTERN (scope); > variadic = true; > } > + if (identifier_p (name) > + && IDENTIFIER_CONV_OP_P (name) > + && PACK_EXPANSION_P (TREE_TYPE (name))) > + { > + name = make_conv_op_name (PACK_EXPANSION_PATTERN > + (TREE_TYPE (name))); > + variadic = true; > + } > dump_type (pp, scope, flags); > pp_cxx_colon_colon (pp); > } > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index 03550308365..2e2d81c1316 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -21705,7 +21705,38 @@ cp_parser_using_declaration (cp_parser* parser, > pedwarn (ell->location, OPT_Wc__17_extensions, > "pack expansion in using-declaration only available " > "with %<-std=c++17%> or %<-std=gnu++17%>"); > - qscope = make_pack_expansion (qscope); > + > + /* A parameter pack can appear in the qualifying scope, and/or in the > + terminal name (if naming a conversion function). Logically they're > + part of a single pack expansion of the overall USING_DECL, but we > + express them as separate pack expansions within the USING_DECL since > + we can't create a pack expansion over a USING_DECL. */ > + bool saw_parm_pack = false; > + if (uses_parameter_packs (qscope)) > + { > + qscope = make_pack_expansion (qscope); > + saw_parm_pack = true; > + } > + /* It can also appear in the terminal name (if naming a conversion > + function). */ > + if (identifier_p (identifier) > + && IDENTIFIER_CONV_OP_P (identifier) > + && uses_parameter_packs (TREE_TYPE (identifier))) > + { > + identifier = make_conv_op_name (make_pack_expansion > + (TREE_TYPE (identifier))); > + saw_parm_pack = true; > + } > + if (!saw_parm_pack) > + { > + /* Issue an error in terms using a SCOPE_REF that includes both > + components. */ > + tree name > + = build_qualified_name (NULL_TREE, qscope, identifier, false); > + make_pack_expansion (name); > + gcc_assert (seen_error ()); > + qscope = identifier = error_mark_node; > + } > } > > /* The function we call to handle a using-declaration is different > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 44058d30799..2fb7d6832ea 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -14963,43 +14963,84 @@ 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 (int i = 0; i < TREE_VEC_LENGTH (name); i++) > + TREE_VEC_ELT (name, i) > + = make_conv_op_name (TREE_VEC_ELT (name, i)); > + 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; > + if (TREE_VEC_LENGTH (scope) != TREE_VEC_LENGTH (name)) > + { > + error ("mismatched argument pack lengths"); > + 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; > + } > else > { > - TREE_PROTECTED (r) = TREE_PROTECTED (t); > - TREE_PRIVATE (r) = TREE_PRIVATE (t); > + 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 > { > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C > new file mode 100644 > index 00000000000..7a8bcbbe372 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C > @@ -0,0 +1,29 @@ > +// PR c++/102104 > +// { dg-do compile { target c++17 } } > + > +struct A { > + using target_type = bool*; > + operator bool*(); > +}; > + > +struct B { > + using target_type = long*; > + operator long*(); > +}; > + > +template<typename... Bases> > +struct cls : private Bases... { > + using Bases::operator typename Bases::target_type...; > +}; > + > +cls<A, B> v1; > +bool* a1 = v1; > +long* b1 = v1; > + > +cls<B> v2; > +bool* a2 = v2; // { dg-error "cannot convert" } > +long* b2 = v2; > + > +cls<A> v3; > +bool* a3 = v3; > +long* b3 = v3; // { dg-error "cannot convert" } > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C > new file mode 100644 > index 00000000000..0393cab6ace > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C > @@ -0,0 +1,34 @@ > +// PR c++/102104 > +// A version of using-variadic1.C where the qualifying scope and the > +// terminal name of the using-declaration use different parameter packs. > +// { dg-do compile { target c++17 } } > + > +struct A { > + using target_type = bool*; > + operator bool*(); > +}; > + > +struct B { > + using target_type = long*; > + operator long*(); > +}; > + > +template<typename... Bases> > +struct cls { > + template<class... Ts> > + struct nested : private Bases... { > + using Bases::operator typename Ts::target_type...; > + }; > +}; > + > +cls<A, B>::nested<A, B> v1; > +bool* a1 = v1; > +long* b1 = v1; > + > +cls<B>::nested<B> v2; > +bool* a2 = v2; // { dg-error "cannot convert" } > +long* b2 = v2; > + > +cls<A>::nested<A> v3; > +bool* a3 = v3; > +long* b3 = v3; // { dg-error "cannot convert" } > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C > new file mode 100644 > index 00000000000..fd3a41718b6 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C > @@ -0,0 +1,37 @@ > +// PR c++/102104 > +// A version of using-variadic1.C where only the qualifying scope > +// uses a parameter pack. > +// { dg-do compile { target c++17 } } > + > +struct A { > + using target_type = bool*; > +}; > + > +struct B { > + using target_type = long*; > +}; > + > +struct C { > + operator bool*(); > + operator long*(); > +}; > + > +template<typename Base> > +struct cls { > + template<class... Ts> > + struct nested : private Base { > + using Base::operator typename Ts::target_type...; > + }; > +}; > + > +cls<C>::nested<A, B> v1; > +bool* a1 = v1; > +long* b1 = v1; > + > +cls<C>::nested<B> v2; > +bool* a2 = v2; // { dg-error "inaccessible|not an accessible" } > +long* b2 = v2; > + > +cls<C>::nested<A> v3; > +bool* a3 = v3; > +long* b3 = v3; // { dg-error "inaccessible|not an accessible" } > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C > new file mode 100644 > index 00000000000..aa86b28fd2e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C > @@ -0,0 +1,33 @@ > +// PR c++/102104 > +// A version of of using-variadic1.C where only the terminal name > +// uses a parameter pack. > +// { dg-do compile { target c++17 } } > + > +struct A { > + operator bool*(); > +}; > + > +struct B { > + operator bool*(); > +}; > + > +struct C { > + using target_type = bool*; > +}; > + > +template<typename... Bases> > +struct cls { > + template<class T> > + struct nested : private Bases... { > + using Bases::operator typename T::target_type...; > + }; > +}; > + > +cls<A, B>::nested<C> v1; > +bool* a1 = v1; // { dg-error "ambiguous" } > + > +cls<A>::nested<C> v2; > +bool* a2 = v2; > + > +cls<B>::nested<C> v3; > +bool* a3 = v3; > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C > new file mode 100644 > index 00000000000..1d68ceece8a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C > @@ -0,0 +1,24 @@ > +// PR c++/102104 > +// A version of using-variadic1a.C where the argument packs have > +// different lengths. > +// { dg-do compile { target c++17 } } > + > +struct A { > + using target_type = bool*; > + operator bool*(); > +}; > + > +struct B { > + using target_type = long*; > + operator long*(); > +}; > + > +template<typename... Bases> > +struct cls { > + template<class... Ts> > + struct nested : private Bases... { > + using Bases::operator typename Ts::target_type...; // { dg-error "lengths" } > + }; > +}; > + > +cls<A>::nested<A, B> v1; // { dg-message "required from here" } > diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C > new file mode 100644 > index 00000000000..4e1d6894e56 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C > @@ -0,0 +1,8 @@ > +// PR c++/108090 > +// { dg-do compile { target c++17 } } > + > +template<typename T> struct As { operator T(); }; > +template<typename ...T> struct AsAll : As<T>... { > + using As<T>::operator T...; > +}; > +AsAll<int, float, char> x;
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 12b28e8ee5b..e7f60335cc0 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -1477,11 +1477,20 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) if (!(flags & TFF_UNQUALIFIED_NAME)) { tree scope = USING_DECL_SCOPE (t); + tree name = DECL_NAME (t); if (PACK_EXPANSION_P (scope)) { scope = PACK_EXPANSION_PATTERN (scope); variadic = true; } + if (identifier_p (name) + && IDENTIFIER_CONV_OP_P (name) + && PACK_EXPANSION_P (TREE_TYPE (name))) + { + name = make_conv_op_name (PACK_EXPANSION_PATTERN + (TREE_TYPE (name))); + variadic = true; + } dump_type (pp, scope, flags); pp_cxx_colon_colon (pp); } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 03550308365..2e2d81c1316 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -21705,7 +21705,38 @@ cp_parser_using_declaration (cp_parser* parser, pedwarn (ell->location, OPT_Wc__17_extensions, "pack expansion in using-declaration only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); - qscope = make_pack_expansion (qscope); + + /* A parameter pack can appear in the qualifying scope, and/or in the + terminal name (if naming a conversion function). Logically they're + part of a single pack expansion of the overall USING_DECL, but we + express them as separate pack expansions within the USING_DECL since + we can't create a pack expansion over a USING_DECL. */ + bool saw_parm_pack = false; + if (uses_parameter_packs (qscope)) + { + qscope = make_pack_expansion (qscope); + saw_parm_pack = true; + } + /* It can also appear in the terminal name (if naming a conversion + function). */ + if (identifier_p (identifier) + && IDENTIFIER_CONV_OP_P (identifier) + && uses_parameter_packs (TREE_TYPE (identifier))) + { + identifier = make_conv_op_name (make_pack_expansion + (TREE_TYPE (identifier))); + saw_parm_pack = true; + } + if (!saw_parm_pack) + { + /* Issue an error in terms using a SCOPE_REF that includes both + components. */ + tree name + = build_qualified_name (NULL_TREE, qscope, identifier, false); + make_pack_expansion (name); + gcc_assert (seen_error ()); + qscope = identifier = error_mark_node; + } } /* The function we call to handle a using-declaration is different diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 44058d30799..2fb7d6832ea 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -14963,43 +14963,84 @@ 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 (int i = 0; i < TREE_VEC_LENGTH (name); i++) + TREE_VEC_ELT (name, i) + = make_conv_op_name (TREE_VEC_ELT (name, i)); + 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; + if (TREE_VEC_LENGTH (scope) != TREE_VEC_LENGTH (name)) + { + error ("mismatched argument pack lengths"); + 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; + } else { - TREE_PROTECTED (r) = TREE_PROTECTED (t); - TREE_PRIVATE (r) = TREE_PRIVATE (t); + 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 { diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C new file mode 100644 index 00000000000..7a8bcbbe372 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1.C @@ -0,0 +1,29 @@ +// PR c++/102104 +// { dg-do compile { target c++17 } } + +struct A { + using target_type = bool*; + operator bool*(); +}; + +struct B { + using target_type = long*; + operator long*(); +}; + +template<typename... Bases> +struct cls : private Bases... { + using Bases::operator typename Bases::target_type...; +}; + +cls<A, B> v1; +bool* a1 = v1; +long* b1 = v1; + +cls<B> v2; +bool* a2 = v2; // { dg-error "cannot convert" } +long* b2 = v2; + +cls<A> v3; +bool* a3 = v3; +long* b3 = v3; // { dg-error "cannot convert" } diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C new file mode 100644 index 00000000000..0393cab6ace --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1a.C @@ -0,0 +1,34 @@ +// PR c++/102104 +// A version of using-variadic1.C where the qualifying scope and the +// terminal name of the using-declaration use different parameter packs. +// { dg-do compile { target c++17 } } + +struct A { + using target_type = bool*; + operator bool*(); +}; + +struct B { + using target_type = long*; + operator long*(); +}; + +template<typename... Bases> +struct cls { + template<class... Ts> + struct nested : private Bases... { + using Bases::operator typename Ts::target_type...; + }; +}; + +cls<A, B>::nested<A, B> v1; +bool* a1 = v1; +long* b1 = v1; + +cls<B>::nested<B> v2; +bool* a2 = v2; // { dg-error "cannot convert" } +long* b2 = v2; + +cls<A>::nested<A> v3; +bool* a3 = v3; +long* b3 = v3; // { dg-error "cannot convert" } diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C new file mode 100644 index 00000000000..fd3a41718b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1b.C @@ -0,0 +1,37 @@ +// PR c++/102104 +// A version of using-variadic1.C where only the qualifying scope +// uses a parameter pack. +// { dg-do compile { target c++17 } } + +struct A { + using target_type = bool*; +}; + +struct B { + using target_type = long*; +}; + +struct C { + operator bool*(); + operator long*(); +}; + +template<typename Base> +struct cls { + template<class... Ts> + struct nested : private Base { + using Base::operator typename Ts::target_type...; + }; +}; + +cls<C>::nested<A, B> v1; +bool* a1 = v1; +long* b1 = v1; + +cls<C>::nested<B> v2; +bool* a2 = v2; // { dg-error "inaccessible|not an accessible" } +long* b2 = v2; + +cls<C>::nested<A> v3; +bool* a3 = v3; +long* b3 = v3; // { dg-error "inaccessible|not an accessible" } diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C new file mode 100644 index 00000000000..aa86b28fd2e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic1c.C @@ -0,0 +1,33 @@ +// PR c++/102104 +// A version of of using-variadic1.C where only the terminal name +// uses a parameter pack. +// { dg-do compile { target c++17 } } + +struct A { + operator bool*(); +}; + +struct B { + operator bool*(); +}; + +struct C { + using target_type = bool*; +}; + +template<typename... Bases> +struct cls { + template<class T> + struct nested : private Bases... { + using Bases::operator typename T::target_type...; + }; +}; + +cls<A, B>::nested<C> v1; +bool* a1 = v1; // { dg-error "ambiguous" } + +cls<A>::nested<C> v2; +bool* a2 = v2; + +cls<B>::nested<C> v3; +bool* a3 = v3; diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C new file mode 100644 index 00000000000..1d68ceece8a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic2.C @@ -0,0 +1,24 @@ +// PR c++/102104 +// A version of using-variadic1a.C where the argument packs have +// different lengths. +// { dg-do compile { target c++17 } } + +struct A { + using target_type = bool*; + operator bool*(); +}; + +struct B { + using target_type = long*; + operator long*(); +}; + +template<typename... Bases> +struct cls { + template<class... Ts> + struct nested : private Bases... { + using Bases::operator typename Ts::target_type...; // { dg-error "lengths" } + }; +}; + +cls<A>::nested<A, B> v1; // { dg-message "required from here" } diff --git a/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C b/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C new file mode 100644 index 00000000000..4e1d6894e56 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using-variadic3.C @@ -0,0 +1,8 @@ +// PR c++/108090 +// { dg-do compile { target c++17 } } + +template<typename T> struct As { operator T(); }; +template<typename ...T> struct AsAll : As<T>... { + using As<T>::operator T...; +}; +AsAll<int, float, char> x;