[C++] Fix tsubst of structured bindings (PR c++/86836)

Message ID 20180803155435.GQ17988@tucnak
State New
Headers show
Series
  • [C++] Fix tsubst of structured bindings (PR c++/86836)
Related show

Commit Message

Jakub Jelinek Aug. 3, 2018, 3:54 p.m.
Hi!

As mentioned in the PR, for valid structured bindings this patch should be
unnecessary, because the identifiers from the structured binding shouldn't
be used in the initializer of the structured binding, but for invalid source
it can matter.  When tsubst_init is called before tsubst_decomp_names,
the local specializations for the decomp id VAR_DECLs aren't created and
so the tsubst of those VAR_DECLs gives the PARM_DECL in this testcase, or
something else unrelated to the decomp.

Fixed by doing tsubst_decomp_names first, then tsubst_init the initializer
and then the rest.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and 8.3
after a while?

2018-08-03  Jakub Jelinek  <jakub@redhat.com>

	PR c++/86836
	* pt.c (tsubst_expr): For structured bindings, call tsubst_decomp_names
	before tsubst_init, not after it.

	* g++.dg/cpp1z/decomp46.C: New test.


	Jakub

Comments

Jason Merrill Aug. 5, 2018, 2:34 p.m. | #1
OK.

On Sat, Aug 4, 2018 at 1:54 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> As mentioned in the PR, for valid structured bindings this patch should be
> unnecessary, because the identifiers from the structured binding shouldn't
> be used in the initializer of the structured binding, but for invalid source
> it can matter.  When tsubst_init is called before tsubst_decomp_names,
> the local specializations for the decomp id VAR_DECLs aren't created and
> so the tsubst of those VAR_DECLs gives the PARM_DECL in this testcase, or
> something else unrelated to the decomp.
>
> Fixed by doing tsubst_decomp_names first, then tsubst_init the initializer
> and then the rest.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and 8.3
> after a while?
>
> 2018-08-03  Jakub Jelinek  <jakub@redhat.com>
>
>         PR c++/86836
>         * pt.c (tsubst_expr): For structured bindings, call tsubst_decomp_names
>         before tsubst_init, not after it.
>
>         * g++.dg/cpp1z/decomp46.C: New test.
>
> --- gcc/cp/pt.c.jj      2018-08-03 11:36:25.550755429 +0200
> +++ gcc/cp/pt.c 2018-08-03 11:48:51.144567965 +0200
> @@ -16740,7 +16740,17 @@ tsubst_expr (tree t, tree args, tsubst_f
>                 else
>                   {
>                     int const_init = false;
> +                   unsigned int cnt = 0;
> +                   tree first = NULL_TREE, ndecl = error_mark_node;
>                     maybe_push_decl (decl);
> +
> +                   if (VAR_P (decl)
> +                       && DECL_DECOMPOSITION_P (decl)
> +                       && TREE_TYPE (pattern_decl) != error_mark_node)
> +                     ndecl = tsubst_decomp_names (decl, pattern_decl, args,
> +                                                  complain, in_decl, &first,
> +                                                  &cnt);
> +
>                     if (VAR_P (decl)
>                         && DECL_PRETTY_FUNCTION_P (decl))
>                       {
> @@ -16756,23 +16766,14 @@ tsubst_expr (tree t, tree args, tsubst_f
>                     if (VAR_P (decl))
>                       const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
>                                     (pattern_decl));
> -                   if (VAR_P (decl)
> -                       && DECL_DECOMPOSITION_P (decl)
> -                       && TREE_TYPE (pattern_decl) != error_mark_node)
> -                     {
> -                       unsigned int cnt;
> -                       tree first;
> -                       tree ndecl
> -                         = tsubst_decomp_names (decl, pattern_decl, args,
> -                                                complain, in_decl, &first, &cnt);
> -                       if (ndecl != error_mark_node)
> -                         cp_maybe_mangle_decomp (ndecl, first, cnt);
> -                       cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
> -                       if (ndecl != error_mark_node)
> -                         cp_finish_decomp (ndecl, first, cnt);
> -                     }
> -                   else
> -                     cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
> +
> +                   if (ndecl != error_mark_node)
> +                     cp_maybe_mangle_decomp (ndecl, first, cnt);
> +
> +                   cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
> +
> +                   if (ndecl != error_mark_node)
> +                     cp_finish_decomp (ndecl, first, cnt);
>                   }
>               }
>           }
> --- gcc/testsuite/g++.dg/cpp1z/decomp46.C.jj    2018-08-03 12:00:10.524066454 +0200
> +++ gcc/testsuite/g++.dg/cpp1z/decomp46.C       2018-08-03 11:59:49.925018174 +0200
> @@ -0,0 +1,25 @@
> +// PR c++/86836
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +struct A {
> +  int operator*();
> +  void operator++();
> +  bool operator!=(A);
> +};
> +template <typename> class map {
> +public:
> +  A begin();
> +  A end();
> +};
> +
> +template <typename T> void mergemap(map<T> orig, map<T> toadd) {
> +  for (auto p : toadd)
> +    auto [orig] = orig;                // { dg-error "use of 'orig' before deduction of 'auto'" }
> +}                              // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
> +
> +int
> +main() {
> +  map<double> x, y;
> +  mergemap(x, y);
> +}
>
>         Jakub

Patch

--- gcc/cp/pt.c.jj	2018-08-03 11:36:25.550755429 +0200
+++ gcc/cp/pt.c	2018-08-03 11:48:51.144567965 +0200
@@ -16740,7 +16740,17 @@  tsubst_expr (tree t, tree args, tsubst_f
 		else
 		  {
 		    int const_init = false;
+		    unsigned int cnt = 0;
+		    tree first = NULL_TREE, ndecl = error_mark_node;
 		    maybe_push_decl (decl);
+
+		    if (VAR_P (decl)
+			&& DECL_DECOMPOSITION_P (decl)
+			&& TREE_TYPE (pattern_decl) != error_mark_node)
+		      ndecl = tsubst_decomp_names (decl, pattern_decl, args,
+						   complain, in_decl, &first,
+						   &cnt);
+
 		    if (VAR_P (decl)
 			&& DECL_PRETTY_FUNCTION_P (decl))
 		      {
@@ -16756,23 +16766,14 @@  tsubst_expr (tree t, tree args, tsubst_f
 		    if (VAR_P (decl))
 		      const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
 				    (pattern_decl));
-		    if (VAR_P (decl)
-			&& DECL_DECOMPOSITION_P (decl)
-			&& TREE_TYPE (pattern_decl) != error_mark_node)
-		      {
-			unsigned int cnt;
-			tree first;
-			tree ndecl
-			  = tsubst_decomp_names (decl, pattern_decl, args,
-						 complain, in_decl, &first, &cnt);
-			if (ndecl != error_mark_node)
-			  cp_maybe_mangle_decomp (ndecl, first, cnt);
-			cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
-			if (ndecl != error_mark_node)
-			  cp_finish_decomp (ndecl, first, cnt);
-		      }
-		    else
-		      cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
+
+		    if (ndecl != error_mark_node)
+		      cp_maybe_mangle_decomp (ndecl, first, cnt);
+
+		    cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
+
+		    if (ndecl != error_mark_node)
+		      cp_finish_decomp (ndecl, first, cnt);
 		  }
 	      }
 	  }
--- gcc/testsuite/g++.dg/cpp1z/decomp46.C.jj	2018-08-03 12:00:10.524066454 +0200
+++ gcc/testsuite/g++.dg/cpp1z/decomp46.C	2018-08-03 11:59:49.925018174 +0200
@@ -0,0 +1,25 @@ 
+// PR c++/86836
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A {
+  int operator*();
+  void operator++();
+  bool operator!=(A);
+};
+template <typename> class map {
+public:
+  A begin();
+  A end();
+};
+
+template <typename T> void mergemap(map<T> orig, map<T> toadd) {
+  for (auto p : toadd)
+    auto [orig] = orig;		// { dg-error "use of 'orig' before deduction of 'auto'" }
+}				// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+
+int
+main() {
+  map<double> x, y;
+  mergemap(x, y);
+}