llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Matthias Görgens (matthiasgoergens)

<details>
<summary>Changes</summary>

Fixes llvm/llvm-project#<!-- -->212467.

## Cause

`mergeErrorAttr` used `AttributeCommonInfo::getNormalizedFullName()` to
decide whether a new diagnostic attribute was an error or a warning.
Contrary to the helper's assertion, a C++11 namespaced GNU spelling produces
`gnu::warning` or `gnu::error`, rather than the unqualified string.

## Trigger (how the bug manifests)

Reproduced on current main (2026-08-03): an assertions build from the
unmodified base exits 134 (assertion abort in `SemaDeclAttr.cpp`) when two
`[[gnu::warning]]` attributes are placed on one declaration. Even a release
Clang rejects identical C23 attributes as incompatible, so the bug also
changes non-asserting-build semantics — not merely a debug-build crash.

## Fix

Construct the generated `ErrorAttr` first and use its semantic `isError()`
and `isWarning()` predicates. These deliberately group GNU, C++11, and C23
spellings of the same attribute while retaining the existing same-kind,
differing-message, and error-versus-warning merge behaviour. A second commit
adds a C23 regression test.

## Verification

- The unmodified compiler exits 134 at the reported assertion; the patched
  compiler accepts the same declaration.
- The C++ regression covers duplicate warning and error attributes,
  differing messages, an incompatible error/warning pair, and both orders of
  mixed GNU and C++11 syntax. The added C23 regression covers both
  diagnostic kinds and both mixed GNU/C23 orders.
- Both focused tests pass in a fresh current-main assertions build. The
  patched compiler also accepts the release-build C23 negative control
  without diagnostics.
- All 3,059 tests in `clang/test/Sema`, `clang/test/SemaCXX`, and
  `clang/test/Frontend` pass, apart from the suite's supported skips and
  expected failure.
- `git diff --check` passes.
- Independent adversarial review checked all six generated spellings,
  incompatible attributes, redeclarations, inheritance, allocation lifetime,
  and diagnostic preservation, and found no blocker.

---
Full diff: https://github.com/llvm/llvm-project/pull/214523.diff


3 Files Affected:

- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+4-6) 
- (added) clang/test/Sema/gh212467.c (+16) 
- (added) clang/test/SemaCXX/gh212467.cpp (+23) 


``````````diff
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 0645f99492433..09ee3988baf3e 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4056,12 +4056,10 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
 
 ErrorAttr *Sema::mergeErrorAttr(Decl *D, const AttributeCommonInfo &CI,
                                 StringRef NewUserDiagnostic) {
+  auto *NewAttr = ::new (Context) ErrorAttr(Context, CI, NewUserDiagnostic);
   if (const auto *EA = D->getAttr<ErrorAttr>()) {
-    std::string NewAttr = CI.getNormalizedFullName();
-    assert((NewAttr == "error" || NewAttr == "warning") &&
-           "unexpected normalized full name");
-    bool Match = (EA->isError() && NewAttr == "error") ||
-                 (EA->isWarning() && NewAttr == "warning");
+    bool Match = (EA->isError() && NewAttr->isError()) ||
+                 (EA->isWarning() && NewAttr->isWarning());
     if (!Match) {
       Diag(EA->getLocation(), diag::err_attributes_are_not_compatible)
           << CI << EA
@@ -4076,7 +4074,7 @@ ErrorAttr *Sema::mergeErrorAttr(Decl *D, const 
AttributeCommonInfo &CI,
     }
     D->dropAttr<ErrorAttr>();
   }
-  return ::new (Context) ErrorAttr(Context, CI, NewUserDiagnostic);
+  return NewAttr;
 }
 
 FormatAttr *Sema::mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI,
diff --git a/clang/test/Sema/gh212467.c b/clang/test/Sema/gh212467.c
new file mode 100644
index 0000000000000..c57d87f13a2db
--- /dev/null
+++ b/clang/test/Sema/gh212467.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+[[gnu::warning("same")]]
+[[gnu::warning("same")]]
+void same_warning(void);
+
+[[gnu::error("same")]]
+[[gnu::error("same")]]
+void same_error(void);
+
+[[gnu::warning("same")]]
+__attribute__((warning("same"))) void mixed_warning(void);
+
+__attribute__((error("same")))
+[[gnu::error("same")]] void reverse_mixed_error(void);
diff --git a/clang/test/SemaCXX/gh212467.cpp b/clang/test/SemaCXX/gh212467.cpp
new file mode 100644
index 0000000000000..38c760f55a084
--- /dev/null
+++ b/clang/test/SemaCXX/gh212467.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+[[gnu::warning("same")]]
+[[gnu::warning("same")]]
+void same_warning();
+
+[[gnu::warning("one")]] // expected-note {{previous attribute is here}}
+[[gnu::warning("two")]] // expected-warning {{attribute 'gnu::warning' is 
already applied with different arguments}}
+void different_warning();
+
+[[gnu::error("same")]]
+[[gnu::error("same")]]
+void same_error();
+
+[[gnu::error("one")]]   // expected-error {{'gnu::warning' and 'gnu::error' 
attributes are not compatible}}
+[[gnu::warning("two")]] // expected-note {{conflicting attribute is here}}
+void conflicting();
+
+[[gnu::warning("same")]]
+__attribute__((warning("same"))) void mixed_syntax();
+
+__attribute__((warning("same")))
+[[gnu::warning("same")]] void reverse_mixed_syntax();

``````````

</details>


https://github.com/llvm/llvm-project/pull/214523
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to