re PR c++/89767 (ICE with tuple and optimization)
authorJakub Jelinek <jakub@redhat.com>
Thu, 21 Mar 2019 22:01:02 +0000 (23:01 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 21 Mar 2019 22:01:02 +0000 (23:01 +0100)
PR c++/89767
* parser.c (cp_parser_lambda_introducer): Add ids and first_capture_id
variables, check for duplicates in this function.
* lambda.c (add_capture): Don't check for duplicates nor use
IDENTIFIER_MARKED.
(register_capture_members): Don't clear IDENTIFIER_MARKED here.

* g++.dg/cpp1y/lambda-init18.C: New test.
* g++.dg/cpp1y/lambda-init19.C: New test.
* g++.dg/cpp1y/pr89767.C: New test.

From-SVN: r269860

gcc/cp/ChangeLog
gcc/cp/lambda.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/lambda-init18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/lambda-init19.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/pr89767.C [new file with mode: 0644]

index 5a28c96..741ad48 100644 (file)
@@ -1,3 +1,12 @@
+2019-03-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/89767
+       * parser.c (cp_parser_lambda_introducer): Add ids and first_capture_id
+       variables, check for duplicates in this function.
+       * lambda.c (add_capture): Don't check for duplicates nor use
+       IDENTIFIER_MARKED.
+       (register_capture_members): Don't clear IDENTIFIER_MARKED here.
+
 2019-03-21  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/89571
index e7f0fda..3e17676 100644 (file)
@@ -601,19 +601,6 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
          IDENTIFIER_LENGTH (id) + 1);
   name = get_identifier (buf);
 
-  /* If TREE_TYPE isn't set, we're still in the introducer, so check
-     for duplicates.  */
-  if (!LAMBDA_EXPR_CLOSURE (lambda))
-    {
-      if (IDENTIFIER_MARKED (name))
-       {
-         pedwarn (input_location, 0,
-                  "already captured %qD in lambda expression", id);
-         return NULL_TREE;
-       }
-      IDENTIFIER_MARKED (name) = true;
-    }
-
   if (variadic)
     type = make_pack_expansion (type);
 
@@ -674,8 +661,6 @@ register_capture_members (tree captures)
   if (PACK_EXPANSION_P (field))
     field = PACK_EXPANSION_PATTERN (field);
 
-  /* We set this in add_capture to avoid duplicates.  */
-  IDENTIFIER_MARKED (DECL_NAME (field)) = false;
   finish_member_declaration (field);
 }
 
index 81aff35..c669e49 100644 (file)
@@ -10547,6 +10547,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
        error ("non-local lambda expression cannot have a capture-default");
     }
 
+  hash_set<tree, true> ids;
+  tree first_capture_id = NULL_TREE;
   while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
     {
       cp_token* capture_token;
@@ -10582,11 +10584,14 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
            pedwarn (loc, 0, "explicit by-copy capture of %<this%> redundant "
                     "with by-copy capture default");
          cp_lexer_consume_token (parser->lexer);
-         add_capture (lambda_expr,
-                      /*id=*/this_identifier,
-                      /*initializer=*/finish_this_expr (),
-                      /*by_reference_p=*/true,
-                      explicit_init_p);
+         if (LAMBDA_EXPR_THIS_CAPTURE (lambda_expr))
+           pedwarn (input_location, 0,
+                    "already captured %qD in lambda expression",
+                    this_identifier);
+         else
+           add_capture (lambda_expr, /*id=*/this_identifier,
+                        /*initializer=*/finish_this_expr (),
+                        /*by_reference_p=*/true, explicit_init_p);
          continue;
        }
 
@@ -10600,11 +10605,14 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
                             "%<-std=c++17%> or %<-std=gnu++17%>");
          cp_lexer_consume_token (parser->lexer);
          cp_lexer_consume_token (parser->lexer);
-         add_capture (lambda_expr,
-                      /*id=*/this_identifier,
-                      /*initializer=*/finish_this_expr (),
-                      /*by_reference_p=*/false,
-                      explicit_init_p);
+         if (LAMBDA_EXPR_THIS_CAPTURE (lambda_expr))
+           pedwarn (input_location, 0,
+                    "already captured %qD in lambda expression",
+                    this_identifier);
+         else
+           add_capture (lambda_expr, /*id=*/this_identifier,
+                        /*initializer=*/finish_this_expr (),
+                        /*by_reference_p=*/false, explicit_init_p);
          continue;
        }
 
@@ -10753,11 +10761,28 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
                     "default", capture_id);
        }
 
-      add_capture (lambda_expr,
-                  capture_id,
-                  capture_init_expr,
-                  /*by_reference_p=*/capture_kind == BY_REFERENCE,
-                  explicit_init_p);
+      /* Check for duplicates.
+        Optimize for the zero or one explicit captures cases and only create
+        the hash_set after adding second capture.  */
+      bool found = false;
+      if (ids.elements ())
+       found = ids.add (capture_id);
+      else if (first_capture_id == NULL_TREE)
+       first_capture_id = capture_id;
+      else if (capture_id == first_capture_id)
+       found = true;
+      else
+       {
+         ids.add (first_capture_id);
+         ids.add (capture_id);
+       }
+      if (found)
+       pedwarn (input_location, 0,
+                "already captured %qD in lambda expression", capture_id);
+      else
+       add_capture (lambda_expr, capture_id, capture_init_expr,
+                    /*by_reference_p=*/capture_kind == BY_REFERENCE,
+                    explicit_init_p);
 
       /* If there is any qualification still in effect, clear it
         now; we will be starting fresh with the next capture.  */
index f575c0f..2334e97 100644 (file)
@@ -1,3 +1,10 @@
+2019-03-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/89767
+       * g++.dg/cpp1y/lambda-init18.C: New test.
+       * g++.dg/cpp1y/lambda-init19.C: New test.
+       * g++.dg/cpp1y/pr89767.C: New test.
+
 2019-03-21  Thomas Schwinge  <thomas@codesourcery.com>
            Cesar Philippidis  <cesar@codesourcery.com>
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init18.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init18.C
new file mode 100644 (file)
index 0000000..5a86600
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/89767
+// { dg-do compile { target c++14 } }
+
+void bar (int);
+
+void
+foo ()
+{
+  int x = 0;
+  auto z = [x, y = [x] { bar (x); }] { y (); bar (x); };
+  z ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-init19.C b/gcc/testsuite/g++.dg/cpp1y/lambda-init19.C
new file mode 100644 (file)
index 0000000..830ecc0
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/89767
+// { dg-do compile { target c++14 } }
+
+void bar (int);
+
+void
+foo ()
+{
+  int x = 0;
+  int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0;
+  auto z = [x, y = [x] { bar (x); }, x] { y (); bar (x); };    // { dg-error "already captured 'x' in lambda expression" }
+  auto w = [x, a, b, c, d, y = [x] { bar (x); }, e, f, g, h, x] { y (); bar (x + a + b + c + d + e + f + g + h); };    // { dg-error "already captured 'x' in lambda expression" }
+  z ();
+  w ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr89767.C b/gcc/testsuite/g++.dg/cpp1y/pr89767.C
new file mode 100644 (file)
index 0000000..108de51
--- /dev/null
@@ -0,0 +1,32 @@
+// PR c++/89767
+// { dg-do compile { target c++14 } }
+// { dg-options "-O2 -Wall" }
+
+template <typename d> struct e { using g = d; };
+template <typename d, template <typename> class> using h = e<d>;
+template <typename d, template <typename> class i>
+using j = typename h<d, i>::g;
+template <typename c> int k(c);
+template <typename...> class au;
+struct l { template <typename c> using m = typename c::f; };
+struct s : l { using af = j<au<int, int> *, m>; };
+template <unsigned long, typename> struct o;
+template <long p, typename c> using q = typename o<p, c>::g;
+template <typename> struct r;
+template <typename c> struct r<c *> { typedef c aj; };
+template <typename ak, typename> struct al { typename r<ak>::aj operator*(); void operator++(); };
+template <typename am, typename an, typename ao>
+bool operator!=(al<am, ao>, al<an, ao>);
+template <unsigned long, typename...> struct ap;
+template <unsigned long aq, typename ar, typename... as>
+struct ap<aq, ar, as...> : ap<1, as...> {};
+template <unsigned long aq, typename ar> struct ap<aq, ar> {};
+template <typename... at> class au : public ap<0, at...> {};
+template <unsigned long p, typename ar, typename... as>
+struct o<p, au<ar, as...>> : o<p - 1, au<as...>> {};
+template <typename ar, typename... as> struct o<0, au<ar, as...>> { typedef ar g; };
+template <long p, typename ar> constexpr ar av(ap<p, ar> __t) { return ar (); }
+template <int p, typename... at> constexpr q<p, au<at...>> aw(au<at...> __t) { av<p>(__t); return q<p, au<at...>> (); }
+struct bg { typedef s::af af; };
+struct F { typedef al<bg::af, int> bk; bk begin(); bk end(); };
+void bo() { int t = 0; F cv; for (auto bp : cv) [t, n = k(aw<1>(bp))] {}; }