https://github.com/vsapsai updated 
https://github.com/llvm/llvm-project/pull/208348

>From 6b6264b4a39d0427ad9aad3eba2f6f5c9926a270 Mon Sep 17 00:00:00 2001
From: Volodymyr Sapsai <[email protected]>
Date: Wed, 8 Jul 2026 15:47:11 -0700
Subject: [PATCH 1/2] [Modules] Handle decl attributes on deserialization the
 same as during parsing.

Replace manual handling of 2 attributes with `Sema::mergeDeclAttributes`,
which is called during parsing too. Also propagate attributes not from
a previous redeclaration but from a previous redeclaration outside of
the current module. This is done to avoid double propagation because attributes
from a previous decl in the same module are already handled when a module
is built.

Call `ASTDeclReader::attachLatestDecl` after each decl is added to
a redeclaration chain, not once per `ASTReader::loadPendingDeclChain` call.
This is done to maintain correct redeclaration chain for each
`ASTDeclReader::attachPreviousDecl` call because [newly added]
`mergeDeclAttributes` requires a correct redeclaration chain.

Separated `Parser::Initialize` and `Parser::ConsumeToken` so can move
the initialization earlier. This way `Parser::Initialize`, `Sema::Initialize`,
`ASTReader::InitializeSema` are executed before deserialization. This specific
case is verified by "Modules/decl-attr-merge-explicit-modules.c".

rdar://175997317
---
 clang/include/clang/Parse/Parser.h            |  3 +-
 clang/lib/Interpreter/IncrementalParser.cpp   |  1 +
 clang/lib/Parse/ParseAST.cpp                  |  3 +-
 clang/lib/Parse/ParseHLSLRootSignature.cpp    |  1 +
 clang/lib/Parse/Parser.cpp                    |  3 -
 clang/lib/Serialization/ASTReaderDecl.cpp     | 55 +++++--------
 .../decl-attr-merge-explicit-modules.c        | 79 +++++++++++++++++++
 clang/test/Modules/decl-attr-merge2.c         | 38 +++++++++
 .../declare_variant_construct_codegen_1.c     |  2 +-
 9 files changed, 142 insertions(+), 43 deletions(-)
 create mode 100644 clang/test/Modules/decl-attr-merge-explicit-modules.c
 create mode 100644 clang/test/Modules/decl-attr-merge2.c

diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index f0e06473bf615..c2b1d0b380185 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -304,8 +304,9 @@ class Parser : public CodeCompletionHandler {
   typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
   typedef OpaquePtr<TemplateName> TemplateTy;
 
-  /// Initialize - Warm up the parser.
+  /// Prepare the parser and its components.
   ///
+  /// The lack of initialization can lead to missing functionality.
   void Initialize();
 
   /// Parse the first top-level declaration in a translation unit.
diff --git a/clang/lib/Interpreter/IncrementalParser.cpp 
b/clang/lib/Interpreter/IncrementalParser.cpp
index f6d2779d64b2b..3cce05b7923ec 100644
--- a/clang/lib/Interpreter/IncrementalParser.cpp
+++ b/clang/lib/Interpreter/IncrementalParser.cpp
@@ -44,6 +44,7 @@ IncrementalParser::IncrementalParser(CompilerInstance 
&Instance,
     External->StartTranslationUnit(Consumer);
 
   P->Initialize();
+  P->ConsumeToken();
 }
 
 IncrementalParser::~IncrementalParser() { P.reset(); }
diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp
index c8ee625eb57ad..e4222acce97bc 100644
--- a/clang/lib/Parse/ParseAST.cpp
+++ b/clang/lib/Parse/ParseAST.cpp
@@ -131,6 +131,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool 
SkipFunctionBodies) {
   std::unique_ptr<Parser> ParseOP(
       new Parser(S.getPreprocessor(), S, SkipFunctionBodies));
   Parser &P = *ParseOP;
+  P.Initialize();
 
   llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup>
       CleanupPrettyStack(llvm::SavePrettyStackState());
@@ -160,7 +161,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool 
SkipFunctionBodies) {
       }
       return M;
     });
-    P.Initialize();
+    P.ConsumeToken();
     Parser::DeclGroupPtrTy ADecl;
     Sema::ModuleImportState ImportState;
     EnterExpressionEvaluationContext PotentiallyEvaluated(
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 80e81e5c403e1..d31520d916b96 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -1557,6 +1557,7 @@ void HandleRootSignatureTarget(Sema &S, StringRef 
EntryRootSig) {
   bool HaveLexer = S.getPreprocessor().getCurrentLexer();
   if (HaveLexer) {
     P->Initialize();
+    P->ConsumeToken();
     S.ActOnStartOfTranslationUnit();
 
     // Skim through the file to parse to find the define
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 5e1fd4df1a3f0..8e8d6ddbefe6b 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -579,9 +579,6 @@ void Parser::Initialize() {
   }
 
   Actions.Initialize();
-
-  // Prime the lexer look-ahead.
-  ConsumeToken();
 }
 
 void Parser::DestroyTemplateIds() {
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp 
b/clang/lib/Serialization/ASTReaderDecl.cpp
index 25598683d1d62..0cbd25396e7e2 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -286,7 +286,7 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, 
void> {
                                      Decl *Previous, Decl *Canon);
   static void attachPreviousDeclImpl(ASTReader &Reader, ...);
   static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous,
-                                 Decl *Canon);
+                                 Decl *PreviousNonLocal, Decl *Canon);
 
   static void checkMultipleDefinitionInNamedModules(ASTReader &Reader, Decl *D,
                                                     Decl *Previous);
@@ -3646,28 +3646,6 @@ Decl *ASTReader::getMostRecentExistingDecl(Decl *D) {
   return ASTDeclReader::getMostRecentDecl(D->getCanonicalDecl());
 }
 
-namespace {
-void mergeInheritableAttributes(ASTReader &Reader, Decl *D, Decl *Previous) {
-  InheritableAttr *NewAttr = nullptr;
-  ASTContext &Context = Reader.getContext();
-  const auto *IA = Previous->getAttr<MSInheritanceAttr>();
-
-  if (IA && !D->hasAttr<MSInheritanceAttr>()) {
-    NewAttr = cast<InheritableAttr>(IA->clone(Context));
-    NewAttr->setInherited(true);
-    D->addAttr(NewAttr);
-  }
-
-  if (!D->hasAttr<AvailabilityAttr>()) {
-    for (const auto *AA : Previous->specific_attrs<AvailabilityAttr>()) {
-      NewAttr = AA->clone(Context);
-      NewAttr->setInherited(true);
-      D->addAttr(NewAttr);
-    }
-  }
-}
-} // namespace
-
 template<typename DeclT>
 void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
                                            Redeclarable<DeclT> *D,
@@ -3879,7 +3857,8 @@ void 
ASTDeclReader::checkMultipleDefinitionInNamedModules(ASTReader &Reader,
 }
 
 void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
-                                       Decl *Previous, Decl *Canon) {
+                                       Decl *Previous, Decl *PreviousNonLocal,
+                                       Decl *Canon) {
   assert(D && Previous);
 
   switch (D->getKind()) {
@@ -3908,11 +3887,12 @@ void ASTDeclReader::attachPreviousDecl(ASTReader 
&Reader, Decl *D,
     inheritDefaultTemplateArguments(Reader.getContext(),
                                     cast<TemplateDecl>(Previous), TD);
 
-  // If any of the declaration in the chain contains an Inheritable attribute,
-  // it needs to be added to all the declarations in the redeclarable chain.
-  // FIXME: Only the logic of merging MSInheritableAttr is present, it should
-  // be extended for all inheritable attributes.
-  mergeInheritableAttributes(Reader, D, Previous);
+  if (PreviousNonLocal) {
+    if (Sema *S = Reader.getSema()) {
+      if (auto *ND = dyn_cast<NamedDecl>(D))
+        S->mergeDeclAttributes(ND, PreviousNonLocal);
+    }
+  }
 }
 
 template<typename DeclT>
@@ -4560,17 +4540,17 @@ void 
ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
 void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) {
   // Attach FirstLocal to the end of the decl chain.
   Decl *CanonDecl = FirstLocal->getCanonicalDecl();
+  Decl *NonLocalMostRecent = nullptr;
   if (FirstLocal != CanonDecl) {
     Decl *PrevMostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl);
-    ASTDeclReader::attachPreviousDecl(
-        *this, FirstLocal, PrevMostRecent ? PrevMostRecent : CanonDecl,
-        CanonDecl);
+    NonLocalMostRecent = PrevMostRecent ? PrevMostRecent : CanonDecl;
+    ASTDeclReader::attachPreviousDecl(*this, FirstLocal, NonLocalMostRecent,
+                                      NonLocalMostRecent, CanonDecl);
+    ASTDeclReader::attachLatestDecl(CanonDecl, FirstLocal);
   }
 
-  if (!LocalOffset) {
-    ASTDeclReader::attachLatestDecl(CanonDecl, FirstLocal);
+  if (!LocalOffset)
     return;
-  }
 
   // Load the list of other redeclarations from this module file.
   ModuleFile *M = getOwningModuleFile(FirstLocal);
@@ -4604,10 +4584,11 @@ void ASTReader::loadPendingDeclChain(Decl *FirstLocal, 
uint64_t LocalOffset) {
   for (unsigned I = 0, N = Record.size(); I != N; ++I) {
     unsigned Idx = N - I - 1;
     auto *D = ReadDecl(*M, Record, Idx);
-    ASTDeclReader::attachPreviousDecl(*this, D, MostRecent, CanonDecl);
+    ASTDeclReader::attachPreviousDecl(*this, D, MostRecent, NonLocalMostRecent,
+                                      CanonDecl);
     MostRecent = D;
+    ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
   }
-  ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
 }
 
 namespace {
diff --git a/clang/test/Modules/decl-attr-merge-explicit-modules.c 
b/clang/test/Modules/decl-attr-merge-explicit-modules.c
new file mode 100644
index 0000000000000..5b31171a3404f
--- /dev/null
+++ b/clang/test/Modules/decl-attr-merge-explicit-modules.c
@@ -0,0 +1,79 @@
+// Check merging attributes when modules are built explicitly.
+//
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-name=first -xc %t/headers/first.modulemap -emit-module -o 
%t/first.pcm
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-name=second -xc %t/headers/second.modulemap -emit-module -o 
%t/second.pcm
+
+// Without module names.
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-file=%t/first.pcm -fmodule-file=%t/second.pcm -fsyntax-only 
%t/test.c -verify
+// With module names.
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-file=first=%t/first.pcm -fmodule-file=second=%t/second.pcm 
-fsyntax-only %t/test.c -verify
+
+// Reverse order.
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-file=%t/second.pcm -fmodule-file=%t/first.pcm -fsyntax-only 
%t/test-reverse.c -verify
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-file=second=%t/second.pcm -fmodule-file=first=%t/first.pcm 
-fsyntax-only %t/test-reverse.c -verify
+
+// With a transitive module dependency.
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-file=first=%t/first.pcm \
+// RUN:   -fmodule-name=second_transitive -xc 
%t/headers/second-transitive.modulemap -emit-module -o %t/second-transitive.pcm
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-file=%t/second-transitive.pcm -fsyntax-only 
%t/test-transitive.c -verify
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -triple 
arm64-apple-macosx10.7.0 -I%t/headers \
+// RUN:   -fmodule-file=second_transitive=%t/second-transitive.pcm 
-fsyntax-only %t/test-transitive.c -verify
+
+//--- headers/first.h
+// Added "used" attribute to add corresponding `FunctionDecl` to 
`EagerlyDeserializedDecls`.
+void availabilityAttr(void) __attribute__((used)) 
__attribute__((availability(macos,unavailable)));
+//--- headers/first.modulemap
+module first {
+  header "first.h" export *
+}
+
+//--- headers/second.h
+void availabilityAttr(void) __attribute__((used)) 
__attribute__((availability(ios,introduced=4.0)));
+//--- headers/second.modulemap
+module second {
+  header "second.h" export *
+}
+
+//--- headers/second-transitive.h
+#include <first.h>
+void availabilityAttr(void) __attribute__((availability(ios,introduced=4.0)));
+//--- headers/second-transitive.modulemap
+module second_transitive {
+  header "second-transitive.h" export *
+}
+
+//--- test.c
+#include <first.h>
+#include <second.h>
+void test(void) {
+  availabilityAttr();
+  // expected-error@-1 {{'availabilityAttr' is unavailable: not available on 
macOS}}
+  // [email protected]:* {{'availabilityAttr' has been explicitly marked 
unavailable here}}
+}
+
+//--- test-reverse.c
+#include <second.h>
+#include <first.h>
+void test(void) {
+  availabilityAttr();
+  // expected-error@-1 {{'availabilityAttr' is unavailable: not available on 
macOS}}
+  // [email protected]:* {{'availabilityAttr' has been explicitly marked 
unavailable here}}
+}
+
+//--- test-transitive.c
+#include <second-transitive.h>
+void test(void) {
+  availabilityAttr();
+  // expected-error@-1 {{'availabilityAttr' is unavailable: not available on 
macOS}}
+  // [email protected]:* {{'availabilityAttr' has been explicitly marked 
unavailable here}}
+}
diff --git a/clang/test/Modules/decl-attr-merge2.c 
b/clang/test/Modules/decl-attr-merge2.c
new file mode 100644
index 0000000000000..fc84b9df70171
--- /dev/null
+++ b/clang/test/Modules/decl-attr-merge2.c
@@ -0,0 +1,38 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps \
+// RUN:   -fmodules-cache-path=%t/mcache -triple arm64-apple-macosx10.7.0 \
+// RUN:   -I%t/headers -fsyntax-only %t/test.c -verify
+
+// Check more cases of attribute merging across multiple modules.
+
+//--- headers/module.modulemap
+module First {
+  header "first.h" export *
+}
+module Second {
+  header "second.h" export *
+}
+//--- headers/first.h
+void additiveAttr(void) __attribute__((availability(macos,unavailable)));
+void exclusiveAttr(void) __attribute__((hot));
+
+//--- headers/second.h
+void additiveAttr(void) __attribute__((availability(ios,introduced=4.0)));
+void exclusiveAttr(void) __attribute__((cold));
+
+//--- test.c
+#include <first.h>
+#include <second.h>
+
+void test(void) {
+  // Check the attribute from "second.h" doesn't hide the attribute from 
"first.h".
+  additiveAttr();
+  // expected-error@-1 {{'additiveAttr' is unavailable: not available on 
macOS}}
+  // [email protected]:* {{'additiveAttr' has been explicitly marked 
unavailable here}}
+
+  // Check calling a function with `MutualExclusions` attributes.
+  exclusiveAttr();
+  // [email protected]:* {{'cold' and 'hot' attributes are not 
compatible}}
+  // [email protected]:* {{conflicting attribute is here}}
+}
diff --git a/clang/test/OpenMP/declare_variant_construct_codegen_1.c 
b/clang/test/OpenMP/declare_variant_construct_codegen_1.c
index 5e659f05773d1..fbe36d2a31840 100644
--- a/clang/test/OpenMP/declare_variant_construct_codegen_1.c
+++ b/clang/test/OpenMP/declare_variant_construct_codegen_1.c
@@ -28,8 +28,8 @@
 void p_vxv(int *v1, int *v2, int *v3, int n);
 void t_vxv(int *v1, int *v2, int *v3, int n);
 
-#pragma omp declare variant(t_vxv) match(construct={target})
 #pragma omp declare variant(p_vxv) match(construct={parallel})
+#pragma omp declare variant(t_vxv) match(construct={target})
 void vxv(int *v1, int *v2, int *v3, int n) {
     for (int i = 0; i < n; i++) v3[i] = v1[i] * v2[i];
 }

>From cc7c85673936af42694117faada99dc1bb3d2e6d Mon Sep 17 00:00:00 2001
From: Volodymyr Sapsai <[email protected]>
Date: Thu, 9 Jul 2026 18:15:38 -0700
Subject: [PATCH 2/2] Update Parser initialization in LLDB, specifically in
 `ClangModulesDeclVendor`.

---
 .../Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp  | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git 
a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp 
b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index 3784acd511095..05bf869c46f3d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -789,9 +789,10 @@ ClangModulesDeclVendor::Create(Target &target) {
   const bool skipFunctionBodies = false;
   std::unique_ptr<clang::Parser> parser(new clang::Parser(
       instance->getPreprocessor(), instance->getSema(), skipFunctionBodies));
+  parser->Initialize();
 
   instance->getPreprocessor().EnterMainSourceFile();
-  parser->Initialize();
+  parser->ConsumeToken();
 
   clang::Parser::DeclGroupPtrTy parsed;
   auto ImportState = clang::Sema::ModuleImportState::NotACXX20Module;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to