c++: Fix attributes with lambda and trailing return type.
authorJason Merrill <jason@redhat.com>
Tue, 28 Jan 2020 22:41:05 +0000 (17:41 -0500)
committerJason Merrill <jason@redhat.com>
Wed, 29 Jan 2020 22:49:59 +0000 (17:49 -0500)
My fix for 60503 fixed handling of C++11 attributes following the
lambda-declarator.  My patch for 89640 re-added support for GNU attributes,
but attributes after the trailing return type were parsed as applying to the
return type rather than to the function.  This patch adjusts parsing of a
trailing-return-type to ignore GNU attributes at the end of the declaration
so that they will be applied to the declaration as a whole.

I also considered parsing the attributes between the closing paren and the
trailing-return-type, and tried a variety of approaches to implementing
that, but I think it's better to stick with the documented rule that "An
attribute specifier list may appear immediately before the comma, '=' or
semicolon terminating the declaration of an identifier...."  Anyone
disagree?

Meanwhile, C++ committee discussion about the lack of any way to apply
attributes to a lambda op() seems to have concluded that they should go
between the introducer and declarator, so I've implemented that as well.

PR c++/90333
PR c++/89640
PR c++/60503
* parser.c (cp_parser_type_specifier_seq): Don't parse attributes in
a trailing return type.
(cp_parser_lambda_declarator_opt): Parse C++11 attributes before
parens.

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/g++.dg/ext/attr-trailing1.C [new file with mode: 0644]

index 3029714d2828fc64600ac30067fd44e27ca0d9e4..b3075832205fd94d63df82915eeb46169604c9a8 100644 (file)
@@ -1,3 +1,13 @@
+2020-01-29  Jason Merrill  <jason@redhat.com>
+
+       PR c++/90333
+       PR c++/89640
+       PR c++/60503
+       * parser.c (cp_parser_type_specifier_seq): Don't parse attributes in
+       a trailing return type.
+       (cp_parser_lambda_declarator_opt): Parse C++11 attributes before
+       parens.
+
 2020-01-29  Marek Polacek  <polacek@redhat.com>
 
        PR c++/91754 - Fix template arguments comparison with class NTTP.
index b8327823777d7ab501053e50b3010440953ad06e..bd8e524f0780c5b2774306c0de3025a9cf65e843 100644 (file)
@@ -10962,6 +10962,9 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
       ++parser->num_template_parameter_lists;
     }
 
+  /* Committee discussion supports allowing attributes here.  */
+  lambda_specs.attributes = cp_parser_attributes_opt (parser);
+
   /* The parameter-declaration-clause is optional (unless
      template-parameter-list was given), but must begin with an
      opening parenthesis if present.  */
@@ -11097,7 +11100,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 
     fco = grokmethod (&return_type_specs,
                      declarator,
-                     gnu_attrs);
+                     chainon (gnu_attrs, lambda_specs.attributes));
     if (fco != error_mark_node)
       {
        DECL_INITIALIZED_IN_CLASS_P (fco) = 1;
@@ -22277,6 +22280,18 @@ cp_parser_type_specifier_seq (cp_parser* parser,
       /* Check for attributes first.  */
       if (cp_next_tokens_can_be_attribute_p (parser))
        {
+         /* GNU attributes at the end of a declaration apply to the
+            declaration as a whole, not to the trailing return type.  So look
+            ahead to see if these attributes are at the end.  */
+         if (seen_type_specifier && is_trailing_return
+             && cp_next_tokens_can_be_gnu_attribute_p (parser))
+           {
+             size_t n = cp_parser_skip_attributes_opt (parser, 1);
+             cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, n);
+             if (tok->type == CPP_SEMICOLON || tok->type == CPP_COMMA
+                 || tok->type == CPP_EQ || tok->type == CPP_OPEN_BRACE)
+               break;
+           }
          type_specifier_seq->attributes
            = attr_chainon (type_specifier_seq->attributes,
                            cp_parser_attributes_opt (parser));
diff --git a/gcc/testsuite/g++.dg/ext/attr-trailing1.C b/gcc/testsuite/g++.dg/ext/attr-trailing1.C
new file mode 100644 (file)
index 0000000..ff3fb90
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/90333
+// { dg-do compile { target c++11 } }
+
+auto l = [] [[nodiscard]] () -> int { return 0; };
+auto l2 = []() -> int __attribute ((warn_unused_result)) { return 0; };
+auto f() -> int __attribute ((warn_unused_result));
+auto f() -> int { return 0; }
+
+int main()
+{
+  l();                         // { dg-warning "nodiscard" }
+  l2();                                // { dg-warning "unused_result" }
+  f();                         // { dg-warning "unused_result" }
+}