From 39d6d4256d16d676f8b9031c4d1d115ddf4ad76b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 10 May 2023 11:37:04 +0200 Subject: [PATCH] c++: Reject attributes without arguments used as pack expansion [PR109756] 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 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 | 13 ++++++++-- gcc/testsuite/g++.dg/cpp0x/gen-attrs-78.C | 29 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-78.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 7f4bc0f468ed..5feed77c7acd 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -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 index 000000000000..28b95439038f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-78.C @@ -0,0 +1,29 @@ +// PR c++/109756 +// { dg-do compile { target c++11 } } +// { dg-options "-Wno-attributes" } + +template +[[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); -- 2.47.2