diff options
author | Marek Polacek <polacek@redhat.com> | 2022-06-02 15:44:20 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2022-06-04 09:57:28 -0400 |
commit | aec868578d8515763d75693c1fdfbc30ff0a1e68 (patch) | |
tree | 6d8b399e71c72fe20dd46dc97052f3a8faac6179 /gcc | |
parent | ed6fd2aed58f2cca99f15331bf68999c0e6df370 (diff) | |
download | gcc-aec868578d8515763d75693c1fdfbc30ff0a1e68.zip gcc-aec868578d8515763d75693c1fdfbc30ff0a1e68.tar.gz gcc-aec868578d8515763d75693c1fdfbc30ff0a1e68.tar.bz2 |
c++: Allow mixing GNU/std-style attributes [PR69585]
cp_parser_attributes_opt doesn't accept GNU attributes followed by
[[]] attributes and vice versa; only a sequence of attributes of the
same kind. That causes grief for code like:
struct __attribute__ ((may_alias)) alignas (2) struct S { };
or
#define EXPORT __attribute__((visibility("default")))
struct [[nodiscard]] EXPORT F { };
It doesn't seem to a documented restriction, so this patch fixes the
problem.
However, the patch does not touch the C FE. The C FE doesn't have
a counterpart to C++'s cp_parser_attributes_opt -- it only has
c_parser_transaction_attributes (which parses both GNU and [[]]
attributes), but that's TM-specific. The C FE seems to use either
c_parser_gnu_attributes or c_parser_std_attribute_specifier_sequence.
As a consequence, this works:
[[maybe_unused]] __attribute__((deprecated)) void f2 ();
but this doesn't:
__attribute__((deprecated)) [[maybe_unused]] void f1 ();
I'm not sure what, if anything, should be done about this.
PR c++/102399
PR c++/69585
gcc/cp/ChangeLog:
* parser.cc (cp_parser_attributes_opt): Accept GNU attributes
followed by [[]] attributes and vice versa.
gcc/testsuite/ChangeLog:
* g++.dg/ext/attrib65.C: New test.
* g++.dg/ext/attrib66.C: New test.
* g++.dg/ext/attrib67.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/parser.cc | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attrib65.C | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attrib66.C | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attrib67.C | 27 |
4 files changed, 72 insertions, 3 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3fc7344..535bf7e 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -28727,9 +28727,17 @@ cp_nth_tokens_can_be_attribute_p (cp_parser *parser, size_t n) static tree cp_parser_attributes_opt (cp_parser *parser) { - if (cp_next_tokens_can_be_gnu_attribute_p (parser)) - return cp_parser_gnu_attributes_opt (parser); - return cp_parser_std_attribute_spec_seq (parser); + tree attrs = NULL_TREE; + while (true) + { + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + attrs = attr_chainon (attrs, cp_parser_gnu_attributes_opt (parser)); + else if (cp_next_tokens_can_be_std_attribute_p (parser)) + attrs = attr_chainon (attrs, cp_parser_std_attribute_spec_seq (parser)); + else + break; + } + return attrs; } /* Parse an (optional) series of attributes. diff --git a/gcc/testsuite/g++.dg/ext/attrib65.C b/gcc/testsuite/g++.dg/ext/attrib65.C new file mode 100644 index 0000000..0af1387 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib65.C @@ -0,0 +1,7 @@ +// PR c++/102399 +// { dg-do compile { target c++11 } } +// Test mixing the GNU and standard forms of attributes. + +#define EXPORT __attribute__((visibility("default"))) + +struct [[nodiscard]] EXPORT Foo { Foo(); }; diff --git a/gcc/testsuite/g++.dg/ext/attrib66.C b/gcc/testsuite/g++.dg/ext/attrib66.C new file mode 100644 index 0000000..102ed70 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib66.C @@ -0,0 +1,27 @@ +// PR c++/69585 +// { dg-do compile { target c++11 } } + +struct __attribute__ ((aligned (2))) __attribute__ ((may_alias)) +S1 { }; + +struct __attribute__ ((aligned (2))) [[gnu::may_alias]] +S2 { }; + +struct alignas (2) __attribute__ ((may_alias)) +S3 { }; + +struct alignas (2) [[gnu::may_alias]] +S4 { }; + + +struct __attribute__ ((may_alias)) __attribute__ ((aligned (2))) +S1_2 { }; + +struct [[gnu::may_alias]] __attribute__ ((aligned (2))) +S2_2 { }; + +struct __attribute__ ((may_alias)) alignas (2) +S3_2 { }; + +struct [[gnu::may_alias]] alignas (2) +S4_2 { }; diff --git a/gcc/testsuite/g++.dg/ext/attrib67.C b/gcc/testsuite/g++.dg/ext/attrib67.C new file mode 100644 index 0000000..a510766 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib67.C @@ -0,0 +1,27 @@ +// PR c++/69585 +// { dg-do compile { target c++11 } } +// Test mixing the GNU and standard forms of attributes. + +__attribute__((deprecated)) [[maybe_unused]] void f1 (); +[[maybe_unused]] __attribute__((deprecated)) void f2 (); +[[maybe_unused]] __attribute__((deprecated)) [[nodiscard]] int f3 (); +__attribute__((unused)) [[nodiscard]] __attribute__((deprecated)) int f4 (); + +struct [[maybe_unused]] __attribute__((aligned)) S1 { double d; }; +struct __attribute__((aligned)) [[maybe_unused]] S2 { double d; }; + +enum E { + X [[maybe_unused]] __attribute__((unavailable)), + Y __attribute__((unavailable)) [[maybe_unused]], +}; + +void +g ([[maybe_unused]] __attribute__((unavailable)) int i1, + __attribute__((unavailable)) [[maybe_unused]] int i2) +{ + [[maybe_unused]] __attribute__((aligned)) int i3; + __attribute__((aligned)) [[maybe_unused]] int i4; + +[[maybe_unused]] +lab: __attribute__((cold)); +} |