https://github.com/AaronBallman created 
https://github.com/llvm/llvm-project/pull/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.

>From 25ff1b420cb00df0b24160879c60878659ead822 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <[email protected]>
Date: Fri, 26 Jun 2026 07:26:28 -0400
Subject: [PATCH 1/2] Diagnose const and pure attributes on non-function
 declarations

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.
---
 clang/docs/ReleaseNotes.rst                                    | 3 +++
 clang/include/clang/Basic/Attr.td                              | 2 ++
 .../test/Misc/pragma-attribute-supported-attributes-list.test  | 2 ++
 clang/test/Parser/cxx0x-attributes.cpp                         | 2 +-
 clang/test/Parser/cxx0x-keyword-attributes.cpp                 | 2 +-
 5 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a2439ccb0452a..df30002d5ac01 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}}

>From fa158160d0ef3bc860ce483c30294e6a71bfe764 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <[email protected]>
Date: Fri, 26 Jun 2026 07:46:36 -0400
Subject: [PATCH 2/2] Add test coverage

---
 clang/test/Sema/attr-const-pure.c | 57 +++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 clang/test/Sema/attr-const-pure.c

diff --git a/clang/test/Sema/attr-const-pure.c 
b/clang/test/Sema/attr-const-pure.c
new file mode 100644
index 0000000000000..d3cbcb80b9341
--- /dev/null
+++ b/clang/test/Sema/attr-const-pure.c
@@ -0,0 +1,57 @@
+// 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; }
+#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

Reply via email to