c++: Deduce range for structured bindings if expression is not type dependent [PR84469]

Message ID Y4X551/z9F08wuCL@tucnak
State New
Headers
Series c++: Deduce range for structured bindings if expression is not type dependent [PR84469] |

Commit Message

Jakub Jelinek Nov. 29, 2022, 12:24 p.m. UTC
  Hi!

As shown on the decomp56.C testcase, if the range for expression
when using structured bindings is not type dependent, we deduce
the finish the structured binding types only when not in template
(cp_convert_range_for takes care of that), but if in templates,
do_range_for_auto_deduction is called instead and it doesn't handle
structured bindings.  During instantiation they are handled later,
but during the parsing keeping the structured bindings type
dependent when they shouldn't be changes behavior.
The following patch calls cp_finish_decomp even from
do_range_for_auto_deduction.
The patch regresses the OpenMP g++.dg/gomp/for-21.C test (3 errors
are gone), I'll post an incremental patch for it momentarily.

Otherwise bootstrapped/regtested on x86_64-linux and i686-linux,
ok for trunk?

2022-11-29  Jakub Jelinek  <jakub@redhat.com>

	PR c++/84469
	* parser.cc (do_range_for_auto_deduction): Add DECOMP_FIRST_NAME
	and DECOMP_CNT arguments.  Call cp_finish_decomp if DECL
	is a structured binding.
	(cp_parser_range_for): Adjust do_range_for_auto_deduction caller.
	(cp_convert_omp_range_for): Likewise.

	* g++.dg/cpp1z/decomp56.C: New test.
	* g++.dg/gomp/pr84469.C: New test.


	Jakub
  

Patch

--- gcc/cp/parser.cc.jj	2022-11-19 09:21:14.000000000 +0100
+++ gcc/cp/parser.cc	2022-11-25 15:39:15.326262120 +0100
@@ -2342,7 +2342,7 @@  static tree cp_parser_c_for
 static tree cp_parser_range_for
   (cp_parser *, tree, tree, tree, bool, unsigned short, bool);
 static void do_range_for_auto_deduction
-  (tree, tree);
+  (tree, tree, tree, unsigned int);
 static tree cp_parser_perform_range_for_lookup
   (tree, tree *, tree *);
 static tree cp_parser_range_for_member_function
@@ -13668,7 +13668,8 @@  cp_parser_range_for (cp_parser *parser,
       if (!type_dependent_expression_p (range_expr)
 	  /* do_auto_deduction doesn't mess with template init-lists.  */
 	  && !BRACE_ENCLOSED_INITIALIZER_P (range_expr))
-	do_range_for_auto_deduction (range_decl, range_expr);
+	do_range_for_auto_deduction (range_decl, range_expr, decomp_first_name,
+				     decomp_cnt);
     }
   else
     {
@@ -13707,7 +13708,8 @@  build_range_temp (tree range_expr)
    a shortcut version of cp_convert_range_for.  */
 
 static void
-do_range_for_auto_deduction (tree decl, tree range_expr)
+do_range_for_auto_deduction (tree decl, tree range_expr,
+			     tree decomp_first_name, unsigned int decomp_cnt)
 {
   tree auto_node = type_uses_auto (TREE_TYPE (decl));
   if (auto_node)
@@ -13727,6 +13729,8 @@  do_range_for_auto_deduction (tree decl,
 						iter_decl, auto_node,
 						tf_warning_or_error,
 						adc_variable_type);
+	  if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+	    cp_finish_decomp (decl, decomp_first_name, decomp_cnt);
 	}
     }
 }
@@ -42981,15 +42985,21 @@  cp_convert_omp_range_for (tree &this_pre
 	  && !BRACE_ENCLOSED_INITIALIZER_P (init))
 	{
 	  tree d = decl;
+	  tree decomp_first_name = NULL_TREE;
+	  unsigned decomp_cnt = 0;
 	  if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl))
 	    {
 	      tree v = DECL_VALUE_EXPR (decl);
 	      if (TREE_CODE (v) == ARRAY_REF
 		  && VAR_P (TREE_OPERAND (v, 0))
 		  && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
-		d = TREE_OPERAND (v, 0);
+		{
+		  d = TREE_OPERAND (v, 0);
+		  decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+		  decomp_first_name = decl;
+		}
 	    }
-	  do_range_for_auto_deduction (d, init);
+	  do_range_for_auto_deduction (d, init, decomp_first_name, decomp_cnt);
 	}
       cond = global_namespace;
       incr = NULL_TREE;
--- gcc/testsuite/g++.dg/cpp1z/decomp56.C.jj	2022-11-25 15:55:27.673217565 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp56.C	2022-11-25 16:08:28.238930284 +0100
@@ -0,0 +1,29 @@ 
+// PR c++/84469
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A {
+  template <typename T>
+  void bar () const {}
+  template <typename T>
+  void baz () const {}
+};
+struct B { A a; };
+
+template <typename>
+void
+foo ()
+{
+  A a[1][1];
+  for (auto const& [b]: a)	// { dg-warning "structured bindings only available with" "" { target c++14_down } }
+    b.bar<int> ();
+  B c;
+  auto const& [d] = c;		// { dg-warning "structured bindings only available with" "" { target c++14_down } }
+  d.baz<double> ();
+}
+
+int
+main ()
+{
+  foo<int> ();
+}
--- gcc/testsuite/g++.dg/gomp/pr84469.C.jj	2022-11-25 15:57:25.805510359 +0100
+++ gcc/testsuite/g++.dg/gomp/pr84469.C	2022-11-25 16:08:40.123758315 +0100
@@ -0,0 +1,24 @@ 
+// PR c++/84469
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A {
+  template <typename T>
+  void bar () const {}
+};
+
+template <typename>
+void
+foo ()
+{
+  A a[1][1];
+  #pragma omp for
+  for (auto const& [b]: a)	// { dg-warning "structured bindings only available with" "" { target c++14_down } }
+    b.bar<int> ();
+}
+
+int
+main ()
+{
+  foo<int> ();
+}