Author: Aaron Ballman Date: 2026-06-26T10:01:11-04:00 New Revision: 64a5845b4f8b64b586f38cabae1d677100e346df
URL: https://github.com/llvm/llvm-project/commit/64a5845b4f8b64b586f38cabae1d677100e346df DIFF: https://github.com/llvm/llvm-project/commit/64a5845b4f8b64b586f38cabae1d677100e346df.diff LOG: Diagnose const and pure attributes on non-function declarations (#206039) The const and pure attribute may only be applied to a function declaration. However, we were missing a subject list for the attributes and so we would silently accept and retain the attribute on any kind of declaration. Empirical testing suggests that this attribute is not effective with Objective-C method calls or indirect calls and so the subject is limited to just function declarations. Added: clang/test/Sema/attr-const-pure.c Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/Attr.td clang/test/Misc/pragma-attribute-supported-attributes-list.test clang/test/Parser/cxx0x-attributes.cpp clang/test/Parser/cxx0x-keyword-attributes.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d1303d4c98507..7fb3f273c5608 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -526,6 +526,9 @@ Attribute Changes in Clang - The ``modular_format`` attribute now supports the ``fixed`` aspect for C ISO 18037 fixed-point ``printf`` specifiers. +- The ``const`` and ``pure`` attributes only apply to functions; they are now + diagnosed and ignored when applied to anything else. + Improvements to Clang's diagnostics ----------------------------------- - Fixed bug in ``-Wdocumentation`` so that it correctly handles explicit diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index f1ae66bd7f2bb..3f57104d474a7 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1497,6 +1497,7 @@ def Common : InheritableAttr { def Const : InheritableAttr { let Spellings = [GCC<"const">, GCC<"__const">]; + let Subjects = SubjectList<[Function]>; let Documentation = [Undocumented]; let SimpleHandler = 1; } @@ -3157,6 +3158,7 @@ def ArmLocallyStreaming : InheritableAttr, TargetSpecificAttr<TargetAArch64> { def Pure : InheritableAttr { let Spellings = [GCC<"pure">]; + let Subjects = SubjectList<[Function]>; let Documentation = [Undocumented]; let SimpleHandler = 1; } diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 03b9a77ec1814..8bca68e2119e7 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -57,6 +57,7 @@ // CHECK-NEXT: CmseNSEntry (SubjectMatchRule_function) // CHECK-NEXT: Cold (SubjectMatchRule_function) // CHECK-NEXT: Common (SubjectMatchRule_variable) +// CHECK-NEXT: Const (SubjectMatchRule_function) // CHECK-NEXT: ConstInit (SubjectMatchRule_variable_is_global) // CHECK-NEXT: Constructor (SubjectMatchRule_function) // CHECK-NEXT: Consumable (SubjectMatchRule_record) @@ -187,6 +188,7 @@ // CHECK-NEXT: Pointer (SubjectMatchRule_record_not_is_union) // CHECK-NEXT: PointerFieldProtection (SubjectMatchRule_record) // CHECK-NEXT: PreserveNone (SubjectMatchRule_hasType_functionType) +// CHECK-NEXT: Pure (SubjectMatchRule_function) // CHECK-NEXT: RandomizeLayout (SubjectMatchRule_record) // CHECK-NEXT: ReadOnlyPlacement (SubjectMatchRule_record) // CHECK-NEXT: ReentrantCapability (SubjectMatchRule_record, SubjectMatchRule_type_alias) diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp index acef9ca39e012..220fddb98127a 100644 --- a/clang/test/Parser/cxx0x-attributes.cpp +++ b/clang/test/Parser/cxx0x-attributes.cpp @@ -215,7 +215,7 @@ struct [[]] N::S s; // expected-error {{an attribute list cannot appear here}} struct [[]] Template<int> t; // expected-error {{an attribute list cannot appear here}} struct [[]] ::template Template<int> u; // expected-error {{an attribute list cannot appear here}} template struct [[]] Template<char>; // expected-error {{an attribute list cannot appear here}} -template struct __attribute__((pure)) Template<std::size_t>; // We still allow GNU-style attributes here +template struct __attribute__((warn_unused)) Template<std::size_t>; // We still allow GNU-style attributes here template <> struct [[]] Template<void>; enum [[]] E1 {}; diff --git a/clang/test/Parser/cxx0x-keyword-attributes.cpp b/clang/test/Parser/cxx0x-keyword-attributes.cpp index be7423cc7ecee..e044336eb1792 100644 --- a/clang/test/Parser/cxx0x-keyword-attributes.cpp +++ b/clang/test/Parser/cxx0x-keyword-attributes.cpp @@ -179,7 +179,7 @@ struct ATTR_USE N::S s; // expected-error {{'ATTR_NAME' cannot appear here}} struct ATTR_USE Template<int> t; // expected-error {{'ATTR_NAME' cannot appear here}} struct ATTR_USE ::template Template<int> u; // expected-error {{'ATTR_NAME' cannot appear here}} template struct ATTR_USE Template<char>; // expected-error {{'ATTR_NAME' cannot appear here}} -template struct __attribute__((pure)) Template<std::size_t>; // We still allow GNU-style attributes here +template struct __attribute__((warn_unused)) Template<std::size_t>; // We still allow GNU-style attributes here template <> struct ATTR_USE Template<void>; // expected-error {{'ATTR_NAME' only applies to non-K&R-style functions}} enum ATTR_USE E1 {}; // expected-error {{'ATTR_NAME' only applies to non-K&R-style functions}} diff --git a/clang/test/Sema/attr-const-pure.c b/clang/test/Sema/attr-const-pure.c new file mode 100644 index 0000000000000..43e22eb34014d --- /dev/null +++ b/clang/test/Sema/attr-const-pure.c @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -x c++ %s + +// The attributes apply to function declarations, nothing else. +__attribute__((const)) int func1(void); +__attribute__((pure)) int func2(void); + +[[gnu::const]] int func3(int x) { return 12; } +[[gnu::pure]] int func4(int x) { return 12; } + +#ifdef __cplusplus +struct CppTest { + // They are fine on member functions. + __attribute__((const)) int func(); + [[gnu::pure]] int other_func(); + + int another(); + + // Constructors and destructors are not allowed though because they + // notionally return void. + [[__gnu__::__const__]] CppTest(); // expected-warning {{'const' attribute on function returning 'void'; attribute ignored}} + __attribute__((pure)) ~CppTest(); // expected-warning {{'pure' attribute on function returning 'void'; attribute ignored}} +}; + +// Including out-of-line member functions. +__attribute__((pure)) int CppTest::another() { return 12; } + +// They also work on function templates. +template <typename Ty> +__attribute__((const)) int temp_func1(Ty); + +// And specializations, too. +// FIXME: this should be diagnosed because it ends up with both the const and pure attributes. +template <> +[[gnu::pure]] int temp_func1<int>(int) { return 12; } +#endif + +// They do not apply to types, including function pointer types. +int (*fp1)(void) [[gnu::const]]; // expected-warning {{attribute 'gnu::const' ignored, because it cannot be applied to a type}} +int (*fp2)(void) [[gnu::pure]]; // expected-warning {{attribute 'gnu::pure' ignored, because it cannot be applied to a type}} + +struct __attribute__((const)) S1 { // expected-warning {{'const' attribute only applies to functions}} + int x; +}; + +struct __attribute__((pure)) S2 { // expected-warning {{'pure' attribute only applies to functions}} + int x; +}; + +// Or variables, etc. +__attribute__((const)) int variable; // expected-warning {{'const' attribute only applies to functions}} +__attribute__((pure)) typedef int foo; // expected-warning {{'pure' attribute only applies to functions}} + +// The function they apply to should return non-void. +__attribute__((const)) void func5(int x); // expected-warning {{'const' attribute on function returning 'void'; attribute ignored}} +__attribute__((pure)) void func6(int x); // expected-warning {{'pure' attribute on function returning 'void'; attribute ignored}} + +// The attributes cannot be used together. +__attribute__((const, pure)) int func7(void); // expected-warning {{'const' attribute imposes more restrictions; 'pure' attribute ignored}} + +// FIXME: this should also be diagnosed the same as func7. +__attribute__((pure)) int func8(void); +[[gnu::const]] int func8(void) { + return 12; +} + _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
