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( + 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(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 +