Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
41 changes: 41 additions & 0 deletions clang/test/Sema/attr-decl-after-definition-std.c
Original file line number Diff line number Diff line change
@@ -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

Loading