Message ID | 20240625050040.3812713-1-quic_apinski@quicinc.com |
---|---|
State | New |
Headers | show |
Series | c++: structured bindings and lookup of tuple_size/tuple_element [PR115605] | expand |
On Mon, Jun 24, 2024 at 10:00:40PM -0700, Andrew Pinski wrote: > The problem here is even though we pass std namespace to lookup_template_class > as the context, it will look at the current scope for the name too. > The fix is to lookup the qualified name first and then use that > for lookup_template_class. > This is how std::initializer_list is handled in listify. > > Note g++.dg/cpp1z/decomp22.C testcase now fails correctly > with an error, that tuple_size is not in the std namespace. > I copied a fixed up testcase into g++.dg/cpp1z/decomp62.C. > > Bootstrapped and tested on x86_64-linux-gnu with no regressions. > > PR c++/115605 > > gcc/cp/ChangeLog: > > * decl.cc (get_tuple_size): Call lookup_qualified_name > before calling lookup_template_class. > (get_tuple_element_type): Likewise. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp1z/decomp22.C: Expect an error Missing . > * g++.dg/cpp1z/decomp61.C: New test. > * g++.dg/cpp1z/decomp62.C: Copied from decomp22.C > and wrap tuple_size/tuple_element inside std namespace. > > Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com> > --- > gcc/cp/decl.cc | 16 +++++--- > gcc/testsuite/g++.dg/cpp1z/decomp22.C | 2 +- > gcc/testsuite/g++.dg/cpp1z/decomp61.C | 53 +++++++++++++++++++++++++++ > gcc/testsuite/g++.dg/cpp1z/decomp62.C | 23 ++++++++++++ > 4 files changed, 88 insertions(+), 6 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp61.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp62.C > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > index 03deb1493a4..81dde4d51a3 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -9195,10 +9195,13 @@ get_tuple_size (tree type) > { > tree args = make_tree_vec (1); > TREE_VEC_ELT (args, 0) = type; > - tree inst = lookup_template_class (tuple_size_identifier, args, > + tree std_tuple_size = lookup_qualified_name (std_node, tuple_size_identifier); > + if (std_tuple_size == error_mark_node) > + return NULL_TREE; > + tree inst = lookup_template_class (std_tuple_size, args, > /*in_decl*/NULL_TREE, > - /*context*/std_node, > - tf_none); > + /*context*/NULL_TREE, > + tf_warning_or_error); > inst = complete_type (inst); > if (inst == error_mark_node > || !COMPLETE_TYPE_P (inst) > @@ -9224,9 +9227,12 @@ get_tuple_element_type (tree type, unsigned i) > tree args = make_tree_vec (2); > TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i); > TREE_VEC_ELT (args, 1) = type; > - tree inst = lookup_template_class (tuple_element_identifier, args, > + tree std_tuple_elem = lookup_qualified_name (std_node, tuple_element_identifier); This line is too long. > + if (std_tuple_elem == error_mark_node) > + return NULL_TREE; > + tree inst = lookup_template_class (std_tuple_elem, args, > /*in_decl*/NULL_TREE, > - /*context*/std_node, > + /*context*/NULL_TREE, > tf_warning_or_error); > return make_typename_type (inst, type_identifier, > none_type, tf_warning_or_error); > diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp22.C b/gcc/testsuite/g++.dg/cpp1z/decomp22.C > index 9e6b8df486a..4131486e292 100644 > --- a/gcc/testsuite/g++.dg/cpp1z/decomp22.C > +++ b/gcc/testsuite/g++.dg/cpp1z/decomp22.C > @@ -17,5 +17,5 @@ int > foo (C<int> t) > { > auto[x0] = t; // { dg-warning "structured bindings only available with" "" { target c++14_down } } > - return x0; > + return x0; /* { dg-error "cannot convert" } */ > } > diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp61.C b/gcc/testsuite/g++.dg/cpp1z/decomp61.C > new file mode 100644 > index 00000000000..874844b2c61 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/decomp61.C > @@ -0,0 +1,53 @@ > +// PR c++/115605 > +// { dg-do compile { target c++17 } } > +// { dg-options "" } (I don't think you need the empty dg-options here.) The patch looks good to me otherwise, thanks. Marek
On 6/25/24 1:00 AM, Andrew Pinski wrote: > The problem here is even though we pass std namespace to lookup_template_class > as the context, it will look at the current scope for the name too. > The fix is to lookup the qualified name first and then use that > for lookup_template_class. If lookup_template_class is mishandling an explicit context argument, let's fix that rather than work around it. > This is how std::initializer_list is handled in listify. > > Note g++.dg/cpp1z/decomp22.C testcase now fails correctly > with an error, that tuple_size is not in the std namespace. > I copied a fixed up testcase into g++.dg/cpp1z/decomp62.C. > > Bootstrapped and tested on x86_64-linux-gnu with no regressions. > > PR c++/115605 > > gcc/cp/ChangeLog: > > * decl.cc (get_tuple_size): Call lookup_qualified_name > before calling lookup_template_class. > (get_tuple_element_type): Likewise. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp1z/decomp22.C: Expect an error > * g++.dg/cpp1z/decomp61.C: New test. > * g++.dg/cpp1z/decomp62.C: Copied from decomp22.C > and wrap tuple_size/tuple_element inside std namespace. > > Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com> > --- > gcc/cp/decl.cc | 16 +++++--- > gcc/testsuite/g++.dg/cpp1z/decomp22.C | 2 +- > gcc/testsuite/g++.dg/cpp1z/decomp61.C | 53 +++++++++++++++++++++++++++ > gcc/testsuite/g++.dg/cpp1z/decomp62.C | 23 ++++++++++++ > 4 files changed, 88 insertions(+), 6 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp61.C > create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp62.C > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > index 03deb1493a4..81dde4d51a3 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -9195,10 +9195,13 @@ get_tuple_size (tree type) > { > tree args = make_tree_vec (1); > TREE_VEC_ELT (args, 0) = type; > - tree inst = lookup_template_class (tuple_size_identifier, args, > + tree std_tuple_size = lookup_qualified_name (std_node, tuple_size_identifier); > + if (std_tuple_size == error_mark_node) > + return NULL_TREE; > + tree inst = lookup_template_class (std_tuple_size, args, > /*in_decl*/NULL_TREE, > - /*context*/std_node, > - tf_none); > + /*context*/NULL_TREE, > + tf_warning_or_error); > inst = complete_type (inst); > if (inst == error_mark_node > || !COMPLETE_TYPE_P (inst) > @@ -9224,9 +9227,12 @@ get_tuple_element_type (tree type, unsigned i) > tree args = make_tree_vec (2); > TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i); > TREE_VEC_ELT (args, 1) = type; > - tree inst = lookup_template_class (tuple_element_identifier, args, > + tree std_tuple_elem = lookup_qualified_name (std_node, tuple_element_identifier); > + if (std_tuple_elem == error_mark_node) > + return NULL_TREE; > + tree inst = lookup_template_class (std_tuple_elem, args, > /*in_decl*/NULL_TREE, > - /*context*/std_node, > + /*context*/NULL_TREE, > tf_warning_or_error); > return make_typename_type (inst, type_identifier, > none_type, tf_warning_or_error); > diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp22.C b/gcc/testsuite/g++.dg/cpp1z/decomp22.C > index 9e6b8df486a..4131486e292 100644 > --- a/gcc/testsuite/g++.dg/cpp1z/decomp22.C > +++ b/gcc/testsuite/g++.dg/cpp1z/decomp22.C > @@ -17,5 +17,5 @@ int > foo (C<int> t) > { > auto[x0] = t; // { dg-warning "structured bindings only available with" "" { target c++14_down } } > - return x0; > + return x0; /* { dg-error "cannot convert" } */ > } > diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp61.C b/gcc/testsuite/g++.dg/cpp1z/decomp61.C > new file mode 100644 > index 00000000000..874844b2c61 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/decomp61.C > @@ -0,0 +1,53 @@ > +// PR c++/115605 > +// { dg-do compile { target c++17 } } > +// { dg-options "" } > + > +using size_t = decltype(sizeof(0)); > + > +namespace std > +{ > + template<class T> > + struct tuple_size; > + template<size_t, class> > + struct tuple_element; > +} > + > +struct mytuple > +{ > + int t; > + template<size_t> > + int &get() > + { > + return t; > + } > +}; > + > +namespace std > +{ > + template<> > + struct tuple_size<mytuple> > + { > + static constexpr int value = 3; > + }; > + template<size_t I> > + struct tuple_element<I, mytuple> > + { > + using type = int; > + }; > +} > + > +/* The tuple_size/tuple_element lookup should only be from std and not > + from the current scope so these 2 functions should work. */ > +int foo() { > + int const tuple_size = 5; > + mytuple array; > + auto [a, b, c] = array; > + return c; > +} > +int foo1() { > + int const tuple_element = 5; > + mytuple array; > + auto [a, b, c] = array; > + return c; > +} > + > diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp62.C b/gcc/testsuite/g++.dg/cpp1z/decomp62.C > new file mode 100644 > index 00000000000..694f3263bd8 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/decomp62.C > @@ -0,0 +1,23 @@ > +// PR c++/79205 > +// { dg-do compile { target c++11 } } > +// { dg-options "" } > + > +template <unsigned long, typename...> struct B; > +template <unsigned long I, typename H> struct B<I, H> { int b; }; > +template <typename... E> struct C { B<0, E...> c; C (C &) = default; C (C &&); }; > +namespace std { > + template <typename> struct tuple_size; > + template <> struct tuple_size<C<int>> { static constexpr int value = 1; }; > + template <int, typename> struct tuple_element; > + template <typename H, typename... T> > + struct tuple_element<0, C<H, T...>> { typedef int type; }; > +} > +template <int, typename... E> > +int &&get (C<E...> &&); > + > +int > +foo (C<int> t) > +{ > + auto[x0] = t; // { dg-warning "structured bindings only available with" "" { target c++14_down } } > + return x0; > +}
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 03deb1493a4..81dde4d51a3 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -9195,10 +9195,13 @@ get_tuple_size (tree type) { tree args = make_tree_vec (1); TREE_VEC_ELT (args, 0) = type; - tree inst = lookup_template_class (tuple_size_identifier, args, + tree std_tuple_size = lookup_qualified_name (std_node, tuple_size_identifier); + if (std_tuple_size == error_mark_node) + return NULL_TREE; + tree inst = lookup_template_class (std_tuple_size, args, /*in_decl*/NULL_TREE, - /*context*/std_node, - tf_none); + /*context*/NULL_TREE, + tf_warning_or_error); inst = complete_type (inst); if (inst == error_mark_node || !COMPLETE_TYPE_P (inst) @@ -9224,9 +9227,12 @@ get_tuple_element_type (tree type, unsigned i) tree args = make_tree_vec (2); TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i); TREE_VEC_ELT (args, 1) = type; - tree inst = lookup_template_class (tuple_element_identifier, args, + tree std_tuple_elem = lookup_qualified_name (std_node, tuple_element_identifier); + if (std_tuple_elem == error_mark_node) + return NULL_TREE; + tree inst = lookup_template_class (std_tuple_elem, args, /*in_decl*/NULL_TREE, - /*context*/std_node, + /*context*/NULL_TREE, tf_warning_or_error); return make_typename_type (inst, type_identifier, none_type, tf_warning_or_error); diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp22.C b/gcc/testsuite/g++.dg/cpp1z/decomp22.C index 9e6b8df486a..4131486e292 100644 --- a/gcc/testsuite/g++.dg/cpp1z/decomp22.C +++ b/gcc/testsuite/g++.dg/cpp1z/decomp22.C @@ -17,5 +17,5 @@ int foo (C<int> t) { auto[x0] = t; // { dg-warning "structured bindings only available with" "" { target c++14_down } } - return x0; + return x0; /* { dg-error "cannot convert" } */ } diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp61.C b/gcc/testsuite/g++.dg/cpp1z/decomp61.C new file mode 100644 index 00000000000..874844b2c61 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/decomp61.C @@ -0,0 +1,53 @@ +// PR c++/115605 +// { dg-do compile { target c++17 } } +// { dg-options "" } + +using size_t = decltype(sizeof(0)); + +namespace std +{ + template<class T> + struct tuple_size; + template<size_t, class> + struct tuple_element; +} + +struct mytuple +{ + int t; + template<size_t> + int &get() + { + return t; + } +}; + +namespace std +{ + template<> + struct tuple_size<mytuple> + { + static constexpr int value = 3; + }; + template<size_t I> + struct tuple_element<I, mytuple> + { + using type = int; + }; +} + +/* The tuple_size/tuple_element lookup should only be from std and not + from the current scope so these 2 functions should work. */ +int foo() { + int const tuple_size = 5; + mytuple array; + auto [a, b, c] = array; + return c; +} +int foo1() { + int const tuple_element = 5; + mytuple array; + auto [a, b, c] = array; + return c; +} + diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp62.C b/gcc/testsuite/g++.dg/cpp1z/decomp62.C new file mode 100644 index 00000000000..694f3263bd8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/decomp62.C @@ -0,0 +1,23 @@ +// PR c++/79205 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +template <unsigned long, typename...> struct B; +template <unsigned long I, typename H> struct B<I, H> { int b; }; +template <typename... E> struct C { B<0, E...> c; C (C &) = default; C (C &&); }; +namespace std { + template <typename> struct tuple_size; + template <> struct tuple_size<C<int>> { static constexpr int value = 1; }; + template <int, typename> struct tuple_element; + template <typename H, typename... T> + struct tuple_element<0, C<H, T...>> { typedef int type; }; +} +template <int, typename... E> +int &&get (C<E...> &&); + +int +foo (C<int> t) +{ + auto[x0] = t; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + return x0; +}
The problem here is even though we pass std namespace to lookup_template_class as the context, it will look at the current scope for the name too. The fix is to lookup the qualified name first and then use that for lookup_template_class. This is how std::initializer_list is handled in listify. Note g++.dg/cpp1z/decomp22.C testcase now fails correctly with an error, that tuple_size is not in the std namespace. I copied a fixed up testcase into g++.dg/cpp1z/decomp62.C. Bootstrapped and tested on x86_64-linux-gnu with no regressions. PR c++/115605 gcc/cp/ChangeLog: * decl.cc (get_tuple_size): Call lookup_qualified_name before calling lookup_template_class. (get_tuple_element_type): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/decomp22.C: Expect an error * g++.dg/cpp1z/decomp61.C: New test. * g++.dg/cpp1z/decomp62.C: Copied from decomp22.C and wrap tuple_size/tuple_element inside std namespace. Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com> --- gcc/cp/decl.cc | 16 +++++--- gcc/testsuite/g++.dg/cpp1z/decomp22.C | 2 +- gcc/testsuite/g++.dg/cpp1z/decomp61.C | 53 +++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp1z/decomp62.C | 23 ++++++++++++ 4 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp61.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp62.C