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);
}
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;
+ }
+ 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
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
{
--- /dev/null
+// 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" }
--- /dev/null
+// 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" }
--- /dev/null
+// 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" }
--- /dev/null
+// 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;
--- /dev/null
+// 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" }
--- /dev/null
+// 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;