[clang] [APINotes] Apply APINotes to non-global decls in a LinkageSpecDecl (PR #176792)
Gábor Horváth via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 19 10:07:20 PST 2026
https://github.com/Xazax-hun created https://github.com/llvm/llvm-project/pull/176792
We checked if a declaration has a LinkageSpecDecl ancestor and assumed that it would be a declaration in global/namespace scope. This prevented us from applying APINotes to methods or fields of a class that was declared in a LinkageSpecDecl. This PR changes the logic to only check whether the parent DeclContext is a LinkageSpecDecl instead of checking for all the ancestors.
>From a9f5c8f7a4f8bf95d91ea7a86af0cc095a0aa6b6 Mon Sep 17 00:00:00 2001
From: Gabor Horvath <gaborh at apple.com>
Date: Mon, 19 Jan 2026 18:02:47 +0000
Subject: [PATCH] [APINotes] Apply APINotes to non-global decls in a
LinkageSpecDecl
We checked if a declaration has a LinkageSpecDecl ancestor and assumed
that it would be a declaration in global/namespace scope. This prevented
us from applying APINotes to methods or fields of a class that was
declared in a LinkageSpecDecl. This PR changes the logic to only check
whether the parent DeclContext is a LinkageSpecDecl instead of checking
for all the ancestors.
---
clang/lib/Sema/SemaAPINotes.cpp | 4 ++--
clang/test/APINotes/Inputs/Headers/Methods.apinotes | 5 +++++
clang/test/APINotes/Inputs/Headers/Methods.h | 8 ++++++++
clang/test/APINotes/methods.cpp | 5 +++++
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 0d8d0faa59abd..d041d0f1f0a30 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -987,8 +987,8 @@ void Sema::ProcessAPINotes(Decl *D) {
auto *DC = D->getDeclContext();
// Globals.
- if (DC->isFileContext() || DC->isNamespace() || DC->isExternCContext() ||
- DC->isExternCXXContext()) {
+ if (DC->isFileContext() || DC->isNamespace() ||
+ DC->getDeclKind() == Decl::LinkageSpec) {
std::optional<api_notes::Context> APINotesContext =
UnwindNamespaceContext(DC, APINotes);
// Global variables.
diff --git a/clang/test/APINotes/Inputs/Headers/Methods.apinotes b/clang/test/APINotes/Inputs/Headers/Methods.apinotes
index 618c2cb14b47f..397d34a1836fc 100644
--- a/clang/test/APINotes/Inputs/Headers/Methods.apinotes
+++ b/clang/test/APINotes/Inputs/Headers/Methods.apinotes
@@ -9,6 +9,11 @@ Tags:
- Name: getDecremented
Availability: none
AvailabilityMsg: "this should have no effect"
+- Name: IntWrapper2
+ Methods:
+ - Name: getIncremented
+ Availability: none
+ AvailabilityMsg: "oh no"
- Name: Outer
Tags:
- Name: Inner
diff --git a/clang/test/APINotes/Inputs/Headers/Methods.h b/clang/test/APINotes/Inputs/Headers/Methods.h
index cbb57ccd0afbd..d4a90e398c8ae 100644
--- a/clang/test/APINotes/Inputs/Headers/Methods.h
+++ b/clang/test/APINotes/Inputs/Headers/Methods.h
@@ -6,6 +6,14 @@ struct IntWrapper {
IntWrapper operator+(const IntWrapper& RHS) const { return {value + RHS.value}; }
};
+extern "C++" {
+struct IntWrapper2 {
+ int value;
+
+ IntWrapper2 getIncremented() const { return {value + 1}; }
+};
+}
+
struct Outer {
struct Inner {
int value;
diff --git a/clang/test/APINotes/methods.cpp b/clang/test/APINotes/methods.cpp
index 910565745bea2..c215505ea5b72 100644
--- a/clang/test/APINotes/methods.cpp
+++ b/clang/test/APINotes/methods.cpp
@@ -1,6 +1,7 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Methods -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -x c++
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Methods -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter IntWrapper::getIncremented -x c++ | FileCheck --check-prefix=CHECK-METHOD %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Methods -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter IntWrapper2::getIncremented -x c++ | FileCheck --check-prefix=CHECK-METHOD-2 %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Methods -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Outer::Inner::getDecremented -x c++ | FileCheck --check-prefix=CHECK-DEEP-METHOD %s
#include "Methods.h"
@@ -9,6 +10,10 @@
// CHECK-METHOD-NEXT: CXXMethodDecl {{.+}} getIncremented
// CHECK-METHOD: UnavailableAttr {{.+}} <<invalid sloc>> "oh no"
+// CHECK-METHOD-2: Dumping IntWrapper2::getIncremented:
+// CHECK-METHOD-2-NEXT: CXXMethodDecl {{.+}} getIncremented
+// CHECK-METHOD-2: UnavailableAttr {{.+}} <<invalid sloc>> "oh no"
+
// CHECK-DEEP-METHOD: Dumping Outer::Inner::getDecremented:
// CHECK-DEEP-METHOD-NEXT: CXXMethodDecl {{.+}} getDecremented
// CHECK-DEEP-METHOD: UnavailableAttr {{.+}} <<invalid sloc>> "nope"
More information about the cfe-commits
mailing list