https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108796
--- Comment #10 from Aaron Ballman <aaron at aaronballman dot com> --- One other reason for the Clang behavior that may be worth mentioning is that this helps users who wish to migrate away from `__attribute__` and towards `[[]]`. Many (most?) uses of attributes end up behind a macro, so the user may not even be aware which syntax is being used. Consider this contrived example: ``` // LibraryHeader.h #if SOMETHING #define FOO_ATTR __attribute__((foo)) #define BAR_ATTR __attribute__((bar)) #define BAZ_ATTR [[lib::baz]] #elif SOMETHING_ELSE ... #else #define FOO_ATTR #define BAR_ATTR #define BAZ_ATTR #endif // UserCode.c FOO_ATTR BAR_ATTR void func(void) { ... } ``` The user reading UserCode.c has no idea what attribute syntax is being used, nor do they probably care all that much. Under a strict parsing model, trying to add `BAZ_ATTR` to the declaration of `func()` requires the user to be very aware of exactly what each macro expands to, otherwise they might get the order wrong. With a relaxed parsing model, the user doesn't have to care. Additionally, the library header can migrate `BAR_ATTR` to `[[gnu::bar]]` syntax without also migrating `FOO_ATTR` at the same time with less fear of breaking downstream users due to attribute ordering, so this allows for gradual migration to a newer syntax. (It's not "no fear" because `[[]]` has strict appertainment rules, so it's possible for some attributes to break user code when migrating from `__attribute__` to `[[]]` due to differences in appertainment.)