diff mbox

[C++] cp_parser_save_member_function_body fix (PR c++/71909)

Message ID 20160718211438.GI7387@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek July 18, 2016, 9:14 p.m. UTC
Hi!

This patch fixes two issues:
1) as shown in the first testcase, cp_parser_save_member_function_body
   adds the catch (....) { ... } tokens into the saved token range
   even when there is no function try block (missing try keyword)
2) if the method starts with __transaction_{atomic,relaxed}, and
   e.g. contains {}s somewhere in the mem-initializers, then
   cp_parser_save_member_function_body stops saving the tokens early
   instead of late

The following patch attempts to handle the same cases
cp_parser_function_definition_after_declarator handles (ok, ignores
the already unsupported return extension) - note that
cp_parser_txn_attribute_opt handles only a small subset of C++11 attributes
(and only once, not multiple times).

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

2016-07-18  Jakub Jelinek  <jakub@redhat.com>

	PR c++/71909
	* parser.c (cp_parser_save_member_function_body): Consume
	__transaction_relaxed or __transaction_atomic with optional
	attribute.  Only skip catch with block if try keyword is seen.

	* g++.dg/parse/pr71909.C: New test.
	* g++.dg/tm/pr71909.C: New test.


	Jakub

Comments

Jason Merrill July 20, 2016, 1:45 p.m. UTC | #1
OK.

On Mon, Jul 18, 2016 at 5:14 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> This patch fixes two issues:
> 1) as shown in the first testcase, cp_parser_save_member_function_body
>    adds the catch (....) { ... } tokens into the saved token range
>    even when there is no function try block (missing try keyword)
> 2) if the method starts with __transaction_{atomic,relaxed}, and
>    e.g. contains {}s somewhere in the mem-initializers, then
>    cp_parser_save_member_function_body stops saving the tokens early
>    instead of late
>
> The following patch attempts to handle the same cases
> cp_parser_function_definition_after_declarator handles (ok, ignores
> the already unsupported return extension) - note that
> cp_parser_txn_attribute_opt handles only a small subset of C++11 attributes
> (and only once, not multiple times).
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2016-07-18  Jakub Jelinek  <jakub@redhat.com>
>
>         PR c++/71909
>         * parser.c (cp_parser_save_member_function_body): Consume
>         __transaction_relaxed or __transaction_atomic with optional
>         attribute.  Only skip catch with block if try keyword is seen.
>
>         * g++.dg/parse/pr71909.C: New test.
>         * g++.dg/tm/pr71909.C: New test.
>
> --- gcc/cp/parser.c.jj  2016-07-16 10:41:04.000000000 +0200
> +++ gcc/cp/parser.c     2016-07-18 11:47:49.487748010 +0200
> @@ -26044,6 +26044,7 @@ cp_parser_save_member_function_body (cp_
>    cp_token *first;
>    cp_token *last;
>    tree fn;
> +  bool function_try_block = false;
>
>    /* Create the FUNCTION_DECL.  */
>    fn = grokmethod (decl_specifiers, declarator, attributes);
> @@ -26065,9 +26066,43 @@ cp_parser_save_member_function_body (cp_
>    /* Save away the tokens that make up the body of the
>       function.  */
>    first = parser->lexer->next_token;
> +
> +  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRANSACTION_RELAXED))
> +    cp_lexer_consume_token (parser->lexer);
> +  else if (cp_lexer_next_token_is_keyword (parser->lexer,
> +                                          RID_TRANSACTION_ATOMIC))
> +    {
> +      cp_lexer_consume_token (parser->lexer);
> +      /* Match cp_parser_txn_attribute_opt [[ identifier ]].  */
> +      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)
> +         && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)
> +         && (cp_lexer_nth_token_is (parser->lexer, 3, CPP_NAME)
> +             || cp_lexer_nth_token_is (parser->lexer, 3, CPP_KEYWORD))
> +         && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_SQUARE)
> +         && cp_lexer_nth_token_is (parser->lexer, 5, CPP_CLOSE_SQUARE))
> +       {
> +         cp_lexer_consume_token (parser->lexer);
> +         cp_lexer_consume_token (parser->lexer);
> +         cp_lexer_consume_token (parser->lexer);
> +         cp_lexer_consume_token (parser->lexer);
> +         cp_lexer_consume_token (parser->lexer);
> +       }
> +      else
> +       while (cp_next_tokens_can_be_gnu_attribute_p (parser)
> +              && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN))
> +         {
> +           cp_lexer_consume_token (parser->lexer);
> +           if (cp_parser_cache_group (parser, CPP_CLOSE_PAREN, /*depth=*/0))
> +             break;
> +         }
> +    }
> +
>    /* Handle function try blocks.  */
>    if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
> -    cp_lexer_consume_token (parser->lexer);
> +    {
> +      cp_lexer_consume_token (parser->lexer);
> +      function_try_block = true;
> +    }
>    /* We can have braced-init-list mem-initializers before the fn body.  */
>    if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
>      {
> @@ -26085,8 +26120,9 @@ cp_parser_save_member_function_body (cp_
>      }
>    cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
>    /* Handle function try blocks.  */
> -  while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
> -    cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
> +  if (function_try_block)
> +    while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
> +      cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
>    last = parser->lexer->next_token;
>
>    /* Save away the inline definition; we will process it when the
> --- gcc/testsuite/g++.dg/parse/pr71909.C.jj     2016-07-18 11:55:51.169600236 +0200
> +++ gcc/testsuite/g++.dg/parse/pr71909.C        2016-07-18 11:57:09.555599364 +0200
> @@ -0,0 +1,22 @@
> +// PR c++/71909
> +// { dg-do compile }
> +
> +struct S
> +{
> +  S () try : m (0) {}
> +  catch (...) {}
> +  void foo () try {}
> +  catch (int) {}
> +  catch (...) {}
> +  int m;
> +};
> +
> +struct T
> +{
> +  T () : m (0) {}
> +  catch (...) {}       // { dg-error "expected unqualified-id before" }
> +  void foo () {}
> +  catch (int) {}       // { dg-error "expected unqualified-id before" }
> +  catch (...) {}       // { dg-error "expected unqualified-id before" }
> +  int m;
> +};
> --- gcc/testsuite/g++.dg/tm/pr71909.C.jj        2016-07-18 12:01:59.888892245 +0200
> +++ gcc/testsuite/g++.dg/tm/pr71909.C   2016-07-18 12:01:14.000000000 +0200
> @@ -0,0 +1,18 @@
> +// PR c++/71909
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-fgnu-tm" }
> +
> +struct S
> +{
> +  S () __transaction_atomic [[outer]] try : m {0} {} catch (int) {} catch (...) {}
> +  int m;
> +};
> +
> +struct T
> +{
> +  T () __transaction_atomic __attribute__((outer)) try : m {0} {} catch (int) {} catch (...) {}
> +  int m;
> +};
> +
> +void foo () __transaction_atomic [[outer]] try {} catch (int) {} catch (...) {}
> +void bar () __transaction_atomic __attribute__((outer)) try {} catch (int) {} catch (...) {}
>
>         Jakub
diff mbox

Patch

--- gcc/cp/parser.c.jj	2016-07-16 10:41:04.000000000 +0200
+++ gcc/cp/parser.c	2016-07-18 11:47:49.487748010 +0200
@@ -26044,6 +26044,7 @@  cp_parser_save_member_function_body (cp_
   cp_token *first;
   cp_token *last;
   tree fn;
+  bool function_try_block = false;
 
   /* Create the FUNCTION_DECL.  */
   fn = grokmethod (decl_specifiers, declarator, attributes);
@@ -26065,9 +26066,43 @@  cp_parser_save_member_function_body (cp_
   /* Save away the tokens that make up the body of the
      function.  */
   first = parser->lexer->next_token;
+
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRANSACTION_RELAXED))
+    cp_lexer_consume_token (parser->lexer);
+  else if (cp_lexer_next_token_is_keyword (parser->lexer,
+					   RID_TRANSACTION_ATOMIC))
+    {
+      cp_lexer_consume_token (parser->lexer);
+      /* Match cp_parser_txn_attribute_opt [[ identifier ]].  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)
+	  && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)
+	  && (cp_lexer_nth_token_is (parser->lexer, 3, CPP_NAME)
+	      || cp_lexer_nth_token_is (parser->lexer, 3, CPP_KEYWORD))
+	  && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_SQUARE)
+	  && cp_lexer_nth_token_is (parser->lexer, 5, CPP_CLOSE_SQUARE))
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  cp_lexer_consume_token (parser->lexer);
+	  cp_lexer_consume_token (parser->lexer);
+	  cp_lexer_consume_token (parser->lexer);
+	  cp_lexer_consume_token (parser->lexer);
+	}
+      else
+	while (cp_next_tokens_can_be_gnu_attribute_p (parser)
+	       && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN))
+	  {
+	    cp_lexer_consume_token (parser->lexer);
+	    if (cp_parser_cache_group (parser, CPP_CLOSE_PAREN, /*depth=*/0))
+	      break;
+	  }
+    }
+
   /* Handle function try blocks.  */
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
-    cp_lexer_consume_token (parser->lexer);
+    {
+      cp_lexer_consume_token (parser->lexer);
+      function_try_block = true;
+    }
   /* We can have braced-init-list mem-initializers before the fn body.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
     {
@@ -26085,8 +26120,9 @@  cp_parser_save_member_function_body (cp_
     }
   cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
   /* Handle function try blocks.  */
-  while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
-    cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
+  if (function_try_block)
+    while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
+      cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
   last = parser->lexer->next_token;
 
   /* Save away the inline definition; we will process it when the
--- gcc/testsuite/g++.dg/parse/pr71909.C.jj	2016-07-18 11:55:51.169600236 +0200
+++ gcc/testsuite/g++.dg/parse/pr71909.C	2016-07-18 11:57:09.555599364 +0200
@@ -0,0 +1,22 @@ 
+// PR c++/71909
+// { dg-do compile }
+
+struct S
+{
+  S () try : m (0) {}
+  catch (...) {}
+  void foo () try {}
+  catch (int) {}
+  catch (...) {}
+  int m;
+};
+
+struct T
+{
+  T () : m (0) {}
+  catch (...) {}	// { dg-error "expected unqualified-id before" }
+  void foo () {}
+  catch (int) {}	// { dg-error "expected unqualified-id before" }
+  catch (...) {}	// { dg-error "expected unqualified-id before" }
+  int m;
+};
--- gcc/testsuite/g++.dg/tm/pr71909.C.jj	2016-07-18 12:01:59.888892245 +0200
+++ gcc/testsuite/g++.dg/tm/pr71909.C	2016-07-18 12:01:14.000000000 +0200
@@ -0,0 +1,18 @@ 
+// PR c++/71909
+// { dg-do compile { target c++11 } }
+// { dg-options "-fgnu-tm" }
+
+struct S
+{
+  S () __transaction_atomic [[outer]] try : m {0} {} catch (int) {} catch (...) {}
+  int m;
+};
+
+struct T
+{
+  T () __transaction_atomic __attribute__((outer)) try : m {0} {} catch (int) {} catch (...) {}
+  int m;
+};
+
+void foo () __transaction_atomic [[outer]] try {} catch (int) {} catch (...) {}
+void bar () __transaction_atomic __attribute__((outer)) try {} catch (int) {} catch (...) {}