]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Reject attributes without arguments used as pack expansion [PR109756]
authorJakub Jelinek <jakub@redhat.com>
Wed, 10 May 2023 09:37:04 +0000 (11:37 +0200)
committerJakub Jelinek <jakub@redhat.com>
Wed, 10 May 2023 09:37:04 +0000 (11:37 +0200)
The following testcase shows we silently accept (and ignore) attributes without
arguments used as pack expansions.  This is because we call
make_pack_expansion and that starts with
  if (!arg || arg == error_mark_node)
    return arg;
Now, an attribute without arguments like [[noreturn...]] is IMHO always
invalid, in this case for 2 reasons; one is that as it has no arguments,
no pack can be present and second is that the standard says that
attributes need to specially permit uses of parameter pack and doesn't
explicitly permit it for any of the standard attributes (except for alignas?
which has different syntax).
If an attribute has some arguments but doesn't contain packs in those
arguments, make_pack_expansion will already diagnose it.

The patch also changes cp_parser_std_attribute, such that for attributes unknown
to the compiler (or perhaps registered just for -Wno-attributes=) we differentiate
between the attribute having no arguments (in that case we want to diagnose them
when followed by ellipsis even if they are unknown, as they can't contain a pack
in that case) and the case where they do have arguments but we've just skipped over
those arguments because we don't know how to parse them (except that they are
a balanced token sequence) - in that case we really don't know if they contain
packs or not.

2023-05-10  Jakub Jelinek  <jakub@redhat.com>

PR c++/109756
* parser.cc (cp_parser_std_attribute): For unknown attributes with
arguments set TREE_VALUE (attribute) to error_mark_node after skipping
the balanced tokens.
(cp_parser_std_attribute_list): If ... is used after attribute without
arguments, diagnose it and return error_mark_node.  If
TREE_VALUE (attribute) is error_mark_node, don't call
make_pack_expansion nor return early error_mark_node.

* g++.dg/cpp0x/gen-attrs-78.C: New test.

gcc/cp/parser.cc
gcc/testsuite/g++.dg/cpp0x/gen-attrs-78.C [new file with mode: 0644]

index 7f4bc0f468ed8351b8f1a63cc73be6594c59c054..5feed77c7acd0d5193aa4f025abb2b4bd7aea210 100644 (file)
@@ -29467,9 +29467,12 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
          }
 
        /* For unknown attributes, just skip balanced tokens instead of
-          trying to parse the arguments.  */
+          trying to parse the arguments.  Set TREE_VALUE (attribute) to
+          error_mark_node to distinguish skipped arguments from attributes
+          with no arguments.  */
        for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; n; --n)
          cp_lexer_consume_token (parser->lexer);
+       TREE_VALUE (attribute) = error_mark_node;
        return attribute;
       }
 
@@ -29561,7 +29564,13 @@ cp_parser_std_attribute_list (cp_parser *parser, tree attr_ns)
          if (attribute == NULL_TREE)
            error_at (token->location,
                      "expected attribute before %<...%>");
-         else
+         else if (TREE_VALUE (attribute) == NULL_TREE)
+           {
+             error_at (token->location, "attribute with no arguments "
+                                        "contains no parameter packs");
+             return error_mark_node;
+           }
+         else if (TREE_VALUE (attribute) != error_mark_node)
            {
              tree pack = make_pack_expansion (TREE_VALUE (attribute));
              if (pack == error_mark_node)
diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-78.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-78.C
new file mode 100644 (file)
index 0000000..28b9543
--- /dev/null
@@ -0,0 +1,29 @@
+// PR c++/109756
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-attributes" }
+
+template <int ...args>
+[[noreturn...]]                                        // { dg-error "attribute with no arguments contains no parameter packs" }
+[[deprecated...]]                              // { dg-error "attribute with no arguments contains no parameter packs" }
+[[nodiscard...]]                               // { dg-error "attribute with no arguments contains no parameter packs" }
+int foo (int x)
+{
+  switch (x)
+    {
+    case 1:
+      [[likely...]];                           // { dg-error "attribute with no arguments contains no parameter packs" }
+      [[fallthrough...]];                      // { dg-error "attribute with no arguments contains no parameter packs" }
+    case 2:
+      [[unlikely...]];                         // { dg-error "attribute with no arguments contains no parameter packs" }
+
+      break;
+    default:
+      break;
+    }
+  struct T {};
+  struct S { [[no_unique_address...]] T t; };  // { dg-error "attribute with no arguments contains no parameter packs" }
+  for (;;)
+    ;
+}
+
+int a = foo <1, 2, 3> (4);