[clang] Allow some attributes on declarations after definitions (PR #135791)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 15 07:39:57 PDT 2025
https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/135791
The deprecated, maybe_unused, and nodiscard standard attributes may all be applied to a redeclaration after a definition has already appeared. We were previously dropping the attribute in that case, now we retain the attribute after the redeclaration.
Note: someday we may want to tablegen this as part of information from Attr.td. We may also want to relax the restriction here so that the syntax used does not matter. This is an intentionally conservative fix.
Fixes #135481
>From fa878e011da7a04ff53ce706b8a9a4f16f82fc18 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Tue, 15 Apr 2025 10:36:48 -0400
Subject: [PATCH] Allow some attributes on declarations after definitions
The deprecated, maybe_unused, and nodiscard standard attributes may all
be applied to a redeclaration after a definition has already appeared.
We were previously dropping the attribute in that case, now we retain
the attribute after the redeclaration.
Note: someday we may want to tablegen this as part of information from
Attr.td. We may also want to relax the restriction here so that the
syntax used does not matter. This is an intentionally conservative fix.
Fixes #135481
---
clang/docs/ReleaseNotes.rst | 5 +++
clang/lib/Sema/SemaDecl.cpp | 15 +++++++
.../Sema/attr-decl-after-definition-std.c | 41 +++++++++++++++++++
3 files changed, 61 insertions(+)
create mode 100644 clang/test/Sema/attr-decl-after-definition-std.c
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6d1daaa84caaa..0575880fa634e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -427,6 +427,11 @@ Bug Fixes to Attribute Support
- No longer crashing on ``__attribute__((align_value(N)))`` during template
instantiation when the function parameter type is not a pointer or reference.
(#GH26612)
+- Now allowing the ``[[deprecated]]``, ``[[maybe_unused]]``, and
+ ``[[nodiscard]]`` to be applied to a redeclaration after a definition in both
+ C and C++ mode for the standard spellings (other spellings, such as
+ ``__attribute__((unused))`` are still ignored after the definition, though
+ this behavior may be relaxed in the future). (#GH135481)
Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e9805c345b6af..240ce5391af81 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2996,6 +2996,21 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
// msvc will allow a subsequent definition to add an uuid to a class
++I;
continue;
+ } else if (isa<DeprecatedAttr, WarnUnusedResultAttr, UnusedAttr>(
+ NewAttribute) &&
+ NewAttribute->isStandardAttributeSyntax()) {
+ // C++14 [dcl.attr.deprecated]p3: A name or entity declared without the
+ // deprecated attribute can later be re-declared with the attribute and
+ // vice-versa.
+ // C++17 [dcl.attr.unused]p4: A name or entity declared without the
+ // maybe_unused attribute can later be redeclared with the attribute and
+ // vice versa.
+ // C++20 [dcl.attr.nodiscard]p2: A name or entity declared without the
+ // nodiscard attribute can later be redeclared with the attribute and
+ // vice-versa.
+ // C23 6.7.13.3p3, 6.7.13.4p3. and 6.7.13.5p5 give the same allowances.
+ ++I;
+ continue;
} else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) {
if (AA->isAlignas()) {
// C++11 [dcl.align]p6:
diff --git a/clang/test/Sema/attr-decl-after-definition-std.c b/clang/test/Sema/attr-decl-after-definition-std.c
new file mode 100644
index 0000000000000..bab52b4dd97ad
--- /dev/null
+++ b/clang/test/Sema/attr-decl-after-definition-std.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -Wignored-attributes -verify -std=c23 %s
+// RUN: %clang_cc1 -fsyntax-only -Wignored-attributes -verify -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
+
+inline int frob(int x) { return x; }
+
+[[deprecated]] int frob(int); // expected-note 2 {{'frob' has been explicitly marked deprecated here}}
+
+void use1() {
+ // Using this should give a deprecation warning, but not a nodiscard warning.
+ frob(0); // expected-warning {{'frob' is deprecated}}
+}
+
+[[nodiscard]] int frob(int);
+
+void use2() {
+ // This should give both warnings.
+ frob(0); // expected-warning {{'frob' is deprecated}} \
+ expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
+
+[[maybe_unused]] int frob(int);
+
+// Currently, this is only allowed for the standard spelling of the attributes.
+void blob() {} // expected-note {{previous definition is here}}
+__attribute__((deprecated)) void blob(); // expected-warning {{attribute declaration must precede definition}}
+
+// CHECK: FunctionDecl {{.*}} frob
+
+// CHECK: FunctionDecl {{.*}} prev {{.*}} frob
+// CHECK: DeprecatedAttr
+
+// CHECK: FunctionDecl {{.*}} prev {{.*}} frob
+// CHECK: DeprecatedAttr
+// CHECK: WarnUnusedResultAttr
+
+// CHECK: FunctionDecl {{.*}} prev {{.*}} frob
+// CHECK: DeprecatedAttr
+// CHECK: WarnUnusedResultAttr
+// CHECK: UnusedAttr
+
More information about the cfe-commits
mailing list