Implement P0028R4, C++17 using attribute namespaces without repetition
authorJakub Jelinek <jakub@redhat.com>
Tue, 13 Sep 2016 19:20:38 +0000 (21:20 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 13 Sep 2016 19:20:38 +0000 (21:20 +0200)
Implement P0028R4, C++17 using attribute namespaces without repetition
* parser.c (cp_parser_std_attribute): Add ATTR_NS argument.  Diagnose
non-NULL ATTR_NS with scoped attribute token.  Handle non-NULL
ATTR_NS with non-scoped attribute tokens.  Allow named ops in
identifier after ::.
(cp_parser_std_attribute_list): Add ATTR_NS argument, pass it down
to cp_parser_std_attribute calls.
(cp_parser_std_attribute_spec): Parse optional C++17
attribute-using-prefix, adjust grammar in function comment.

* g++.dg/cpp0x/gen-attrs-61.C: New test.
* g++.dg/cpp1z/gen-attrs1.C: New test.

From-SVN: r240121

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/gen-attrs-61.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/gen-attrs1.C [new file with mode: 0644]

index a8407fdaa753a123b764d23865b1b8d611217914..97e9cda97ceca701406184abec4780a581582cf1 100644 (file)
@@ -1,5 +1,15 @@
 2016-09-13  Jakub Jelinek  <jakub@redhat.com>
 
+       Implement P0028R4, C++17 using attribute namespaces without repetition
+       * parser.c (cp_parser_std_attribute): Add ATTR_NS argument.  Diagnose
+       non-NULL ATTR_NS with scoped attribute token.  Handle non-NULL
+       ATTR_NS with non-scoped attribute tokens.  Allow named ops in
+       identifier after ::.
+       (cp_parser_std_attribute_list): Add ATTR_NS argument, pass it down
+       to cp_parser_std_attribute calls.
+       (cp_parser_std_attribute_spec): Parse optional C++17
+       attribute-using-prefix, adjust grammar in function comment.
+
        PR c++/77553
        * constexpr.c (cxx_fold_pointer_plus_expression): New function.
        (cxx_eval_binary_expression): Use it for POINTER_PLUS_EXPR.
index 73a37814b5969c12b4dadafdbbf271be6cc6a5f5..d704593e6aa283819290e82c0f14e2266dfbd112 100644 (file)
@@ -2392,7 +2392,7 @@ static tree cp_parser_gnu_attributes_opt
 static tree cp_parser_gnu_attribute_list
   (cp_parser *);
 static tree cp_parser_std_attribute
-  (cp_parser *);
+  (cp_parser *, tree);
 static tree cp_parser_std_attribute_spec
   (cp_parser *);
 static tree cp_parser_std_attribute_spec_seq
@@ -24056,9 +24056,9 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
       { balanced-token-seq }.  */
 
 static tree
-cp_parser_std_attribute (cp_parser *parser)
+cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 {
-  tree attribute, attr_ns = NULL_TREE, attr_id = NULL_TREE, arguments;
+  tree attribute, attr_id = NULL_TREE, arguments;
   cp_token *token;
 
   /* First, parse name of the attribute, a.k.a attribute-token.  */
@@ -24082,6 +24082,9 @@ cp_parser_std_attribute (cp_parser *parser)
       /* We are seeing a scoped attribute token.  */
 
       cp_lexer_consume_token (parser->lexer);
+      if (attr_ns)
+       error_at (token->location, "attribute using prefix used together "
+                                  "with scoped attribute token");
       attr_ns = attr_id;
 
       token = cp_lexer_consume_token (parser->lexer);
@@ -24089,6 +24092,8 @@ cp_parser_std_attribute (cp_parser *parser)
        attr_id = token->u.value;
       else if (token->type == CPP_KEYWORD)
        attr_id = ridpointers[(int) token->keyword];
+      else if (token->flags & NAMED_OP)
+       attr_id = get_identifier (cpp_type2name (token->type, token->flags));
       else
        {
          error_at (token->location,
@@ -24099,6 +24104,9 @@ cp_parser_std_attribute (cp_parser *parser)
                                   NULL_TREE);
       token = cp_lexer_peek_token (parser->lexer);
     }
+  else if (attr_ns)
+    attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
+                                NULL_TREE);
   else
     {
       attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
@@ -24192,14 +24200,14 @@ cp_parser_check_std_attribute (tree attributes, tree attribute)
 */
 
 static tree
-cp_parser_std_attribute_list (cp_parser *parser)
+cp_parser_std_attribute_list (cp_parser *parser, tree attr_ns)
 {
   tree attributes = NULL_TREE, attribute = NULL_TREE;
   cp_token *token = NULL;
 
   while (true)
     {
-      attribute = cp_parser_std_attribute (parser);
+      attribute = cp_parser_std_attribute (parser, attr_ns);
       if (attribute == error_mark_node)
        break;
       if (attribute != NULL_TREE)
@@ -24227,9 +24235,12 @@ cp_parser_std_attribute_list (cp_parser *parser)
 /* Parse a standard C++-11 attribute specifier.
 
    attribute-specifier:
-     [ [ attribute-list ] ]
+     [ [ attribute-using-prefix [opt] attribute-list ] ]
      alignment-specifier
 
+   attribute-using-prefix:
+     using attribute-namespace :
+
    alignment-specifier:
      alignas ( type-id ... [opt] )
      alignas ( alignment-expression ... [opt] ).  */
@@ -24243,10 +24254,39 @@ cp_parser_std_attribute_spec (cp_parser *parser)
   if (token->type == CPP_OPEN_SQUARE
       && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_SQUARE)
     {
+      tree attr_ns = NULL_TREE;
+
       cp_lexer_consume_token (parser->lexer);
       cp_lexer_consume_token (parser->lexer);
 
-      attributes = cp_parser_std_attribute_list (parser);
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
+       {
+         token = cp_lexer_peek_nth_token (parser->lexer, 2);
+         if (token->type == CPP_NAME)
+           attr_ns = token->u.value;
+         else if (token->type == CPP_KEYWORD)
+           attr_ns = ridpointers[(int) token->keyword];
+         else if (token->flags & NAMED_OP)
+           attr_ns = get_identifier (cpp_type2name (token->type,
+                                                    token->flags));
+         if (attr_ns
+             && cp_lexer_nth_token_is (parser->lexer, 3, CPP_COLON))
+           {
+             if (cxx_dialect < cxx1z
+                 && !in_system_header_at (input_location))
+               pedwarn (input_location, 0,
+                        "attribute using prefix only available "
+                        "with -std=c++1z or -std=gnu++1z");
+
+             cp_lexer_consume_token (parser->lexer);
+             cp_lexer_consume_token (parser->lexer);
+             cp_lexer_consume_token (parser->lexer);
+           }
+         else
+           attr_ns = NULL_TREE;
+       }
+
+      attributes = cp_parser_std_attribute_list (parser, attr_ns);
 
       if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)
          || !cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
index a89273701919c91514a714fc4002b6f30775e94c..779145a05fd7472f3a5ae3a7f7e243695c88c569 100644 (file)
@@ -1,5 +1,8 @@
 2016-09-13  Jakub Jelinek  <jakub@redhat.com>
 
+       * g++.dg/cpp0x/gen-attrs-61.C: New test.
+       * g++.dg/cpp1z/gen-attrs1.C: New test.
+
        PR tree-optimization/77454
        * gcc.dg/pr77454.c: New test.
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-61.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-61.C
new file mode 100644 (file)
index 0000000..fd7f443
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++11 } }
+int
+foo ()
+{
+  int i [[and::bitor, bar::xor_eq, compl::baz(1), bitand::xor_eq(2, 3)]]; // { dg-warning "ignored" }
+  int j [[using, using::baz, bar::using, using::using (2)]];             // { dg-warning "ignored" }
+  i = 0;
+  j = 0;
+  return i + j;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/gen-attrs1.C b/gcc/testsuite/g++.dg/cpp1z/gen-attrs1.C
new file mode 100644 (file)
index 0000000..fe1ebb2
--- /dev/null
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int
+foo ()
+{
+  static int a [[using gnu: unused, used]];    // { dg-warning "attribute using prefix only available" "" { target c++14_down } }
+  int b [[ using foo : bar (2), baz ]];                // { dg-warning "'foo::bar' scoped attribute directive ignored" }
+                                               // { dg-warning "'foo::baz' scoped attribute directive ignored" "" { target *-*-* } 8 }
+                                               // { dg-warning "attribute using prefix only available" "" { target c++14_down } 8 }
+  int c [[ using foo : using ("foo")]];                // { dg-warning "'foo::using' scoped attribute directive ignored" }
+                                               // { dg-warning "attribute using prefix only available" "" { target c++14_down } 11 }
+  b = 0;
+  c = 0;
+  return b + c;
+}
+
+int
+bar ()
+{
+  int a [[ using BAR: foo::bar]];              // { dg-error "attribute using prefix used together with scoped attribute token" }
+                                               // { dg-warning "ignored" "" { target *-*-* } 21 }
+                                               // { dg-warning "attribute using prefix only available" "" { target c++14_down } 21 }
+  int b [[ using BAZ: bar(2), bar::bar(3, 4) ]];// { dg-error "attribute using prefix used together with scoped attribute token" }
+                                               // { dg-warning "ignored" "" { target *-*-* } 24 }
+                                               // { dg-warning "attribute using prefix only available" "" { target c++14_down } 24 }
+  a = 0;
+  b = 0;
+  return a + b;
+}
+
+int
+baz ()
+{
+  int a [[ using using: using]];               // { dg-warning "attribute using prefix only available" "" { target c++14_down } }
+                                               // { dg-warning "'using::using' scoped attribute directive ignored" "" { target *-*-* } 35 }
+  int b [[ using bitand: bitor, xor]];         // { dg-warning "attribute using prefix only available" "" { target c++14_down } }
+                                               // { dg-warning "'bitand::bitor' scoped attribute directive ignored" "" { target *-*-* } 37 }
+                                               // { dg-warning "'bitand::xor' scoped attribute directive ignored" "" { target *-*-* } 37 }
+  a = 0;
+  b = 0;
+  return a + b;
+}