diff mbox series

c++: structured bindings and lookup of tuple_size/tuple_element [PR115605]

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

Commit Message

Andrew Pinski June 25, 2024, 5 a.m. UTC
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

Comments

Marek Polacek June 25, 2024, 4:20 p.m. UTC | #1
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
Jason Merrill July 25, 2024, 6:41 p.m. UTC | #2
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 mbox series

Patch

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;
+}