[clang] [Clang] diagnose unknown attribute namespaces (PR #138519)

Oleksandr T. via cfe-commits cfe-commits at lists.llvm.org
Mon May 5 05:36:23 PDT 2025


https://github.com/a-tarasyuk created https://github.com/llvm/llvm-project/pull/138519

This patch enhances Clang's attribute handling by diagnosing unknown attribute namespaces 

```c++
[[foo::nodiscard]] int f(); // warning: unknown attribute namespace 'unknown'; attribute 'unknown::foo' ignored 
```

>From 7d376b33f09801be504ec65a2853679dff8b726c Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Mon, 5 May 2025 15:30:14 +0300
Subject: [PATCH] [Clang] diagnose unknown attribute namespaces

---
 clang/docs/ReleaseNotes.rst                   |  2 ++
 .../include/clang/Basic/AttributeCommonInfo.h |  4 +++-
 .../clang/Basic/DiagnosticCommonKinds.td      |  3 +++
 clang/lib/Basic/Attributes.cpp                |  9 ++++++++-
 clang/lib/Sema/SemaDeclAttr.cpp               | 19 ++++++++++++-------
 clang/test/CXX/module/module.interface/p3.cpp |  2 +-
 clang/test/Parser/c2x-attributes.c            |  2 +-
 clang/test/Parser/cxx0x-attributes.cpp        |  6 +++---
 clang/test/Sema/unknown-attributes.c          | 12 ++++++++++++
 9 files changed, 45 insertions(+), 14 deletions(-)
 create mode 100644 clang/test/Sema/unknown-attributes.c

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a80fedebf8f89..d01fc5d1bf46f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -385,6 +385,8 @@ related warnings within the method body.
 - Clang now disallows the use of attributes applied before an
   ``extern template`` declaration (#GH79893).
 
+- Clang now diagnoses unknown attribute namespaces
+
 Improvements to Clang's diagnostics
 -----------------------------------
 
diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h
index 4af5a8fd1852c..ddb022c493bdf 100644
--- a/clang/include/clang/Basic/AttributeCommonInfo.h
+++ b/clang/include/clang/Basic/AttributeCommonInfo.h
@@ -67,7 +67,7 @@ class AttributeCommonInfo {
     IgnoredAttribute,
     UnknownAttribute,
   };
-  enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV };
+  enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV, UNKNOWN };
   enum class AttrArgsInfo {
     None,
     Optional,
@@ -234,6 +234,8 @@ class AttributeCommonInfo {
     return SyntaxUsed == AS_ContextSensitiveKeyword;
   }
 
+  bool isUnknownScopeName() const;
+
   unsigned getAttributeSpellingListIndex() const {
     assert((isAttributeSpellingListCalculated() || AttrName) &&
            "Spelling cannot be found");
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index f26c906b46447..63f4c229b2e76 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -177,6 +177,9 @@ def err_opencl_unknown_type_specifier : Error<
   "%0 does not support the '%1' "
   "%select{type qualifier|storage class specifier}2">;
 
+def warn_unknown_attribute_namespace : Warning<
+  "unknown attribute namespace '%0'; attribute '%0::%1' ignored">,
+  InGroup<UnknownAttributes>;
 def warn_unknown_attribute_ignored : Warning<
   "unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
 def warn_attribute_ignored : Warning<"%0 attribute ignored">,
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index 6a070a99c8d96..c41cbf0fb61f6 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -191,7 +191,8 @@ getScopeFromNormalizedScopeName(StringRef ScopeName) {
       .Case("hlsl", AttributeCommonInfo::Scope::HLSL)
       .Case("msvc", AttributeCommonInfo::Scope::MSVC)
       .Case("omp", AttributeCommonInfo::Scope::OMP)
-      .Case("riscv", AttributeCommonInfo::Scope::RISCV);
+      .Case("riscv", AttributeCommonInfo::Scope::RISCV)
+      .Default(AttributeCommonInfo::Scope::UNKNOWN);
 }
 
 unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
@@ -206,3 +207,9 @@ unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
 
 #include "clang/Sema/AttrSpellingListIndex.inc"
 }
+
+bool AttributeCommonInfo::isUnknownScopeName() const {
+  return getScopeFromNormalizedScopeName(
+             normalizeAttrScopeName(getScopeName(), getSyntax())) ==
+         AttributeCommonInfo::Scope::UNKNOWN;
+}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index bfb3ee9dcbd16..7dc5a04923946 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -6861,13 +6861,18 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   // though they were unknown attributes.
   if (AL.getKind() == ParsedAttr::UnknownAttribute ||
       !AL.existsInTarget(S.Context.getTargetInfo())) {
-    S.Diag(AL.getLoc(),
-           AL.isRegularKeywordAttribute()
-               ? (unsigned)diag::err_keyword_not_supported_on_target
-           : AL.isDeclspecAttribute()
-               ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
-               : (unsigned)diag::warn_unknown_attribute_ignored)
-        << AL << AL.getRange();
+    if (AL.isUnknownScopeName())
+      S.Diag(AL.getScopeLoc(), diag::warn_unknown_attribute_namespace)
+          << AL.getScopeName()->getName() << AL.getAttrName()->getName()
+          << SourceRange(AL.getScopeLoc(), AL.getRange().getEnd());
+    else
+      S.Diag(AL.getLoc(),
+             AL.isRegularKeywordAttribute()
+                 ? (unsigned)diag::err_keyword_not_supported_on_target
+             : AL.isDeclspecAttribute()
+                 ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
+                 : (unsigned)diag::warn_unknown_attribute_ignored)
+          << AL << AL.getRange();
     return;
   }
 
diff --git a/clang/test/CXX/module/module.interface/p3.cpp b/clang/test/CXX/module/module.interface/p3.cpp
index 32819b2dccb11..18758edaf1be7 100644
--- a/clang/test/CXX/module/module.interface/p3.cpp
+++ b/clang/test/CXX/module/module.interface/p3.cpp
@@ -40,7 +40,7 @@ export { // No diagnostic after P2615R1 DR
   extern "C++" {} // No diagnostic after P2615R1 DR
 }
 export [[]]; // No diagnostic after P2615R1 DR
-export [[example::attr]]; // expected-warning {{unknown attribute 'attr'}}
+export [[example::attr]]; // expected-warning {{unknown attribute namespace 'example'; attribute 'example::attr' ignored}}
 
 // [...] shall not declare a name with internal linkage
 export static int a; // expected-error {{declaration of 'a' with internal linkage cannot be exported}}
diff --git a/clang/test/Parser/c2x-attributes.c b/clang/test/Parser/c2x-attributes.c
index be039e40f98ef..b5f502c5790d3 100644
--- a/clang/test/Parser/c2x-attributes.c
+++ b/clang/test/Parser/c2x-attributes.c
@@ -133,7 +133,7 @@ void f11(void) {
 }
 
 [[attr]] void f12(void); // expected-warning {{unknown attribute 'attr' ignored}}
-[[vendor::attr]] void f13(void); // expected-warning {{unknown attribute 'attr' ignored}}
+[[vendor::attr]] void f13(void); // expected-warning {{unknown attribute namespace 'vendor'; attribute 'vendor::attr' ignored}}
 
 // Ensure that asm statements properly handle double colons.
 void test_asm(void) {
diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp
index fad3010c98b9c..7a0a8b989851f 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -46,7 +46,7 @@ int & [[noreturn]] ref_attr_3 = after_attr; // expected-error {{'noreturn' attri
 int && [[]] rref_attr = 0;
 int array_attr [1] [[]];
 alignas(8) int aligned_attr;
-[[test::valid(for 42 [very] **** '+' symbols went on a trip and had a "good"_time; the end.)]] int garbage_attr; // expected-warning {{unknown attribute 'valid' ignored}}
+[[test::valid(for 42 [very] **** '+' symbols went on a trip and had a "good"_time; the end.)]] int garbage_attr; // expected-warning {{unknown attribute namespace 'test'; attribute 'test::valid' ignored}}
 [[,,,static, class, namespace,, inline, constexpr, mutable,, bitand, bitor::compl(!.*_ Cx.!U^*R),,,]] int more_garbage_attr; // expected-warning {{unknown attribute 'static' ignored}} \
     // expected-warning {{unknown attribute 'class' ignored}} \
     // expected-warning {{unknown attribute 'namespace' ignored}} \
@@ -54,7 +54,7 @@ alignas(8) int aligned_attr;
     // expected-warning {{unknown attribute 'constexpr' ignored}} \
     // expected-warning {{unknown attribute 'mutable' ignored}} \
     // expected-warning {{unknown attribute 'bitand' ignored}} \
-    // expected-warning {{unknown attribute 'compl' ignored}}
+    // expected-warning {{unknown attribute namespace 'bitor'; attribute 'bitor::compl' ignored}}
 [[u8"invalid!"]] int invalid_string_attr; // expected-error {{expected ']'}}
 void fn_attr () [[]];
 void noexcept_fn_attr () noexcept [[]];
@@ -269,7 +269,7 @@ template <int... Is> void variadic_nttp() {
   void baz [[clang::no_sanitize(Is...)]] ();          // expected-error {{expected string literal as argument of 'no_sanitize' attribute}}
   void bor [[clang::annotate("A", "V" ...)]] ();      // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
   void bir [[clang::annotate("B", {1, 2, 3, 4})]] (); // expected-error {{'annotate' attribute requires parameter 1 to be a constant expression}} expected-note {{subexpression not valid in a constant expression}}
-  void boo [[unknown::foo(Is...)]] ();                // expected-warning {{unknown attribute 'foo' ignored}}
+  void boo [[unknown::foo(Is...)]] ();                // expected-warning {{unknown attribute namespace 'unknown'; attribute 'unknown::foo' ignored}}
   void faz [[clang::annotate("C", (Is + ...))]] ();   // expected-warning {{pack fold expression is a C++17 extension}}
   void far [[clang::annotate("D", Is...)]] ();
   void foz [[clang::annotate("E", 1, 2, 3, Is...)]] ();
diff --git a/clang/test/Sema/unknown-attributes.c b/clang/test/Sema/unknown-attributes.c
new file mode 100644
index 0000000000000..833ac2f919ea6
--- /dev/null
+++ b/clang/test/Sema/unknown-attributes.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -Wunknown-attributes -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -Wunknown-attributes -verify %s
+
+[[foo::a]] // expected-warning {{unknown attribute namespace 'foo'; attribute 'foo::a' ignored}}
+int f1(void) {
+  return 0;
+}
+
+[[clan::deprecated]] // expected-warning {{unknown attribute namespace 'clan'; attribute 'clan::deprecated' ignored}}
+int f2(void) {
+  return 0;
+}



More information about the cfe-commits mailing list