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
