https://github.com/Xazax-hun created https://github.com/llvm/llvm-project/pull/222902
API notes are matched against whichever declaration the compiler reaches, which can be a redeclaration that follows the definition. When the definition lives in one module and the annotated redeclaration in another, that is exactly what happens: checkNewAttributesAfterDef() warns "attribute declaration must precede definition" and erases the attribute, so the annotation is silently lost. The warning exists to tell users that an attribute they wrote has no effect. Attributes from API notes are not written in the source, so the warning has nowhere to point and there is nothing for the user to correct. Skip attributes with an invalid location, alongside the existing exceptions. rdar://186930250 From fa1e1ba081f5bfc75d4cd39f7a82789c0cc0e1eb Mon Sep 17 00:00:00 2001 From: Gabor Horvath <[email protected]> Date: Fri, 11 Sep 2026 10:34:30 +0100 Subject: [PATCH] [clang][APINotes] Do not drop attributes applied after a definition API notes are matched against whichever declaration the compiler reaches, which can be a redeclaration that follows the definition. When the definition lives in one module and the annotated redeclaration in another, that is exactly what happens: checkNewAttributesAfterDef() warns "attribute declaration must precede definition" and erases the attribute, so the annotation is silently lost. The warning exists to tell users that an attribute they wrote has no effect. Attributes from API notes are not written in the source, so the warning has nowhere to point and there is nothing for the user to correct. Skip attributes with an invalid location, alongside the existing exceptions. rdar://186930250 --- clang/lib/Sema/SemaDecl.cpp | 11 +++++++++++ .../APINotes/Inputs/Headers/RedeclAnnotation.apinotes | 5 +++++ clang/test/APINotes/Inputs/Headers/RedeclAnnotation.h | 3 +++ clang/test/APINotes/Inputs/Headers/RedeclDefinition.h | 1 + clang/test/APINotes/Inputs/Headers/module.modulemap | 9 +++++++++ clang/test/APINotes/redecl-after-definition.c | 10 ++++++++++ 6 files changed, 39 insertions(+) create mode 100644 clang/test/APINotes/Inputs/Headers/RedeclAnnotation.apinotes create mode 100644 clang/test/APINotes/Inputs/Headers/RedeclAnnotation.h create mode 100644 clang/test/APINotes/Inputs/Headers/RedeclDefinition.h create mode 100644 clang/test/APINotes/redecl-after-definition.c diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a9047f61a8bf5..5de5821fe263e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3144,6 +3144,17 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { continue; // regular attr merging will take care of validating this. } + if (NewAttribute->getLocation().isInvalid()) { + // An attribute with no source location was not written by the user. API + // notes, in particular, are matched against whichever declaration the + // compiler reaches, which can be a redeclaration that follows the + // definition, possibly in a different module. There is nothing for the + // user to correct, and erasing the attribute would silently change what + // the annotated API means. + ++I; + continue; + } + if (isa<C11NoReturnAttr>(NewAttribute)) { // C's _Noreturn is allowed to be added to a function after it is defined. ++I; diff --git a/clang/test/APINotes/Inputs/Headers/RedeclAnnotation.apinotes b/clang/test/APINotes/Inputs/Headers/RedeclAnnotation.apinotes new file mode 100644 index 0000000000000..512732766fb46 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/RedeclAnnotation.apinotes @@ -0,0 +1,5 @@ +Name: RedeclAnnotation +Functions: +- Name: redeclaredAfterDefinition + Availability: none + AvailabilityMsg: not available diff --git a/clang/test/APINotes/Inputs/Headers/RedeclAnnotation.h b/clang/test/APINotes/Inputs/Headers/RedeclAnnotation.h new file mode 100644 index 0000000000000..6383cee22a833 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/RedeclAnnotation.h @@ -0,0 +1,3 @@ +#include "RedeclDefinition.h" + +int redeclaredAfterDefinition(int x); diff --git a/clang/test/APINotes/Inputs/Headers/RedeclDefinition.h b/clang/test/APINotes/Inputs/Headers/RedeclDefinition.h new file mode 100644 index 0000000000000..5b034df6077df --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/RedeclDefinition.h @@ -0,0 +1 @@ +inline int redeclaredAfterDefinition(int x) { return x; } diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap b/clang/test/APINotes/Inputs/Headers/module.modulemap index 592d482ea7a57..a9b273ccc90e6 100644 --- a/clang/test/APINotes/Inputs/Headers/module.modulemap +++ b/clang/test/APINotes/Inputs/Headers/module.modulemap @@ -75,3 +75,12 @@ module WhereParametersSema { header "WhereParametersSema.h" export * } + +module RedeclDefinition { + header "RedeclDefinition.h" +} + +module RedeclAnnotation { + header "RedeclAnnotation.h" + export * +} diff --git a/clang/test/APINotes/redecl-after-definition.c b/clang/test/APINotes/redecl-after-definition.c new file mode 100644 index 0000000000000..466105d613fee --- /dev/null +++ b/clang/test/APINotes/redecl-after-definition.c @@ -0,0 +1,10 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -verify + +#include "RedeclDefinition.h" +#include "RedeclAnnotation.h" + +void test(void) { + redeclaredAfterDefinition(1); // expected-error{{'redeclaredAfterDefinition' is unavailable: not available}} + // expected-note@Inputs/Headers/RedeclAnnotation.h:3{{'redeclaredAfterDefinition' has been explicitly marked unavailable here}} +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
