https://github.com/anondeveg updated https://github.com/llvm/llvm-project/pull/223044
>From 0c9fb73e29e1c378e0f0c177ed78d2912ff9e6e2 Mon Sep 17 00:00:00 2001 From: Anondev <[email protected]> Date: Fri, 11 Sep 2026 22:51:40 +0300 Subject: [PATCH] [clang][Modules] Add explicit PrivateModuleFragmentDecl AST node --- clang/include/clang/AST/Decl.h | 43 +++++++++++++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 1 + clang/include/clang/AST/TextNodeDumper.h | 1 + clang/include/clang/Basic/DeclNodes.td | 1 + clang/include/clang/Sema/Template.h | 5 ++- .../include/clang/Serialization/ASTBitCodes.h | 5 ++- clang/lib/AST/Decl.cpp | 9 ++++ clang/lib/AST/DeclBase.cpp | 1 + clang/lib/AST/DeclPrinter.cpp | 5 +++ clang/lib/AST/TextNodeDumper.cpp | 5 +++ clang/lib/CodeGen/CGDecl.cpp | 1 + clang/lib/Parse/Parser.cpp | 6 ++- clang/lib/Sema/SemaModule.cpp | 6 ++- clang/lib/Serialization/ASTCommon.cpp | 1 + clang/lib/Serialization/ASTReaderDecl.cpp | 11 +++++ clang/lib/Serialization/ASTWriterDecl.cpp | 8 ++++ .../AST/ast-dump-private-module-fragment.cppm | 12 ++++++ .../mismatched_global_module_state.cppm | 5 +++ clang/tools/libclang/CIndex.cpp | 1 + 19 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 clang/test/AST/ast-dump-private-module-fragment.cppm create mode 100644 clang/test/Modules/mismatched_global_module_state.cppm diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 92050d635e2e0..3fab5e8515bd4 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -5309,6 +5309,49 @@ class ExportDecl final : public Decl, public DeclContext { } }; +/// Represents the private module fragment of a module unit. +/// +/// For example: +/// \code +/// export module A; +/// ... +/// module :private; // <- this fragment +/// int internal_only(); +/// \endcode +class PrivateModuleFragmentDecl final : public Decl { + Module *Fragment; + SourceLocation PrivateLoc; + + PrivateModuleFragmentDecl(DeclContext *DC, SourceLocation ModuleLoc, + SourceLocation PrivateLoc, Module *Fragment) + : Decl(PrivateModuleFragment, DC, ModuleLoc), Fragment(Fragment), + PrivateLoc(PrivateLoc) {} + PrivateModuleFragmentDecl(EmptyShell Empty) + : Decl(PrivateModuleFragment, Empty) {} + +public: + static PrivateModuleFragmentDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation ModuleLoc, + SourceLocation PrivateLoc, + Module *Fragment) { + return new (C, DC) + PrivateModuleFragmentDecl(DC, ModuleLoc, PrivateLoc, Fragment); + } + static PrivateModuleFragmentDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); + + Module *getFragment() const { return Fragment; } + SourceLocation getPrivateLoc() const { return PrivateLoc; } + void setPrivateLoc(SourceLocation Loc) { PrivateLoc = Loc; } + void setFragment(Module *Frag) { Fragment = Frag; } + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getLocation(), PrivateLoc); + } + static bool classof(const Decl *D) { + return D->getKind() == Decl::PrivateModuleFragment; + } +}; + /// Represents an empty-declaration. class EmptyDecl : public Decl { EmptyDecl(DeclContext *DC, SourceLocation L) : Decl(Empty, DC, L) {} diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 1f7c8d762e1b5..24371d148a0a6 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1723,6 +1723,7 @@ DEF_TRAVERSE_DECL(FileScopeAsmDecl, DEF_TRAVERSE_DECL(TopLevelStmtDecl, { TRY_TO(TraverseStmt(D->getStmt())); }) DEF_TRAVERSE_DECL(ImportDecl, {}) +DEF_TRAVERSE_DECL(PrivateModuleFragmentDecl, {}) DEF_TRAVERSE_DECL(FriendDecl, { // Friend is either decl or a type. diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 1cdd8c37c7fc6..d0c97326f85f0 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -373,6 +373,7 @@ class TextNodeDumper void VisitBindingDecl(const BindingDecl *D); void VisitCapturedDecl(const CapturedDecl *D); void VisitImportDecl(const ImportDecl *D); + void VisitPrivateModuleFragmentDecl(const PrivateModuleFragmentDecl *D); void VisitPragmaCommentDecl(const PragmaCommentDecl *D); void VisitPragmaDetectMismatchDecl(const PragmaDetectMismatchDecl *D); void VisitOMPExecutableDirective(const OMPExecutableDirective *D); diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 114c6ae5282ef..0e81a32d19d25 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -107,6 +107,7 @@ def Block : DeclNode<Decl, "blocks">, DeclContext; def OutlinedFunction : DeclNode<Decl>, DeclContext; def Captured : DeclNode<Decl>, DeclContext; def Import : DeclNode<Decl>; +def PrivateModuleFragment : DeclNode<Decl>; def OMPThreadPrivate : DeclNode<Decl>; def OMPGroupPrivate : DeclNode<Decl>; def OMPAllocate : DeclNode<Decl>; diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 50e950e56c6ca..ab1584ee0f1b3 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -634,6 +634,7 @@ enum class TemplateSubstitutionKind : char { #define FILESCOPEASM(DERIVED, BASE) #define TOPLEVELSTMT(DERIVED, BASE) #define IMPORT(DERIVED, BASE) +#define PRIVATEMODULEFRAGMENT(DERIVED, BASE) #define EXPORT(DERIVED, BASE) #define LINKAGESPEC(DERIVED, BASE) #define OBJCCOMPATIBLEALIAS(DERIVED, BASE) @@ -645,10 +646,10 @@ enum class TemplateSubstitutionKind : char { #define EMPTY(DERIVED, BASE) #define LIFETIMEEXTENDEDTEMPORARY(DERIVED, BASE) -// Decls which never appear inside a template. + // Decls which never appear inside a template. #define OUTLINEDFUNCTION(DERIVED, BASE) -// Decls which use special-case instantiation code. + // Decls which use special-case instantiation code. #define BLOCK(DERIVED, BASE) #define CAPTURED(DERIVED, BASE) #define IMPLICITPARAM(DERIVED, BASE) diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 6a52a9e4fa780..722bca1975e40 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1492,7 +1492,10 @@ enum DeclCode { /// An ImportDecl recording a module import. DECL_IMPORT, - /// An OMPThreadPrivateDecl record. + /// A PrivateModuleFragmentDecl record. + DECL_PRIVATE_MODULE_FRAGMENT, + + /// An OMPThreadPrivateDecl Record. DECL_OMP_THREADPRIVATE, /// An OMPRequiresDecl record. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 0894097333d73..01af3f08e418f 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -6192,3 +6192,12 @@ bool clang::hasArmZT0State(const FunctionDecl *FD) { FunctionType::ARM_None) || (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZT0()); } + +//===----------------------------------------------------------------------===// +// PrivateModuleFragmentDecl Implementation +//===----------------------------------------------------------------------===// + +PrivateModuleFragmentDecl * +PrivateModuleFragmentDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { + return new (C, ID) PrivateModuleFragmentDecl(EmptyShell()); +} diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 70f61fa57a682..e89ee3e0f3170 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -986,6 +986,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Friend: case FriendTemplate: case AccessSpec: + case PrivateModuleFragment: case LinkageSpec: case Export: case FileScopeAsm: diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 1312ffd080342..3e0ab4b41797c 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -78,6 +78,7 @@ namespace { void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitTopLevelStmtDecl(TopLevelStmtDecl *D); void VisitImportDecl(ImportDecl *D); + void VisitPrivateModuleFragmentDecl(PrivateModuleFragmentDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); @@ -1065,6 +1066,10 @@ void DeclPrinter::VisitImportDecl(ImportDecl *D) { << ";\n"; } +void DeclPrinter::VisitPrivateModuleFragmentDecl(PrivateModuleFragmentDecl *D) { + Out << "module :private;\n"; +} + void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) { Out << "static_assert("; D->getAssertExpr()->printPretty(Out, nullptr, Policy, Indentation, "\n", diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index f58cc4f5761b7..60312419fa559 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -2643,6 +2643,11 @@ void TextNodeDumper::VisitImportDecl(const ImportDecl *D) { dumpDeclRef(InitD, "initializer"); } +void TextNodeDumper::VisitPrivateModuleFragmentDecl( + const PrivateModuleFragmentDecl *D) { + OS << ' ' << D->getFragment()->getFullModuleName(); +} + void TextNodeDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) { OS << ' '; switch (D->getCommentKind()) { diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index b8fae352d41d7..b5a8f9db06de0 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -128,6 +128,7 @@ void CodeGenFunction::EmitDecl(const Decl &D, bool EvaluateConditionDecl) { case Decl::ExplicitInstantiation: case Decl::Label: // __label__ x; case Decl::Import: + case Decl::PrivateModuleFragment: case Decl::MSGuid: // __declspec(uuid("...")) case Decl::UnnamedGlobalConstant: case Decl::TemplateParamObject: diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index bad81ea92cd2d..7e7efa0df7cfe 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2360,10 +2360,14 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { SourceLocation PrivateLoc = ConsumeToken(); DiagnoseAndSkipCXX11Attributes(); ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi); + auto Result = Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc); + + if (!Result) + return nullptr; ImportState = ImportState == Sema::ModuleImportState::ImportAllowed ? Sema::ModuleImportState::PrivateFragmentImportAllowed : Sema::ModuleImportState::PrivateFragmentImportFinished; - return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc); + return Result; } SmallVector<IdentifierLoc, 2> Path; diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index d7a182fe5654c..91983e4dcbb2b 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -565,8 +565,10 @@ Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); TU->setLocalOwningModule(PrivateModuleFragment); - // FIXME: Consider creating an explicit representation of this declaration. - return nullptr; + auto *PMF = PrivateModuleFragmentDecl::Create( + Context, CurContext, ModuleLoc, PrivateLoc, PrivateModuleFragment); + CurContext->addDecl(PMF); + return ConvertDeclToDeclGroup(PMF); } DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index ca7993adb7d2c..9b2eed7d74b65 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -446,6 +446,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::OutlinedFunction: case Decl::Captured: case Decl::Import: + case Decl::PrivateModuleFragment: case Decl::OMPThreadPrivate: case Decl::OMPGroupPrivate: case Decl::OMPAllocate: diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index e973b7ae71954..d3dc6c33903da 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -402,6 +402,7 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { void VisitTopLevelStmtDecl(TopLevelStmtDecl *D); void VisitImportDecl(ImportDecl *D); void VisitAccessSpecDecl(AccessSpecDecl *D); + void VisitPrivateModuleFragmentDecl(PrivateModuleFragmentDecl *D); void VisitFriendDecl(FriendDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); @@ -2397,6 +2398,13 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) { Record.skipInts(1); // The number of stored source locations. } +void ASTDeclReader::VisitPrivateModuleFragmentDecl( + PrivateModuleFragmentDecl *D) { + VisitDecl(D); + D->setFragment(readModule()); + D->setPrivateLoc(readSourceLocation()); +} + void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { VisitDecl(D); D->setColonLoc(readSourceLocation()); @@ -4278,6 +4286,9 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) { // locations. D = ImportDecl::CreateDeserialized(Context, ID, Record.back()); break; + case DECL_PRIVATE_MODULE_FRAGMENT: + D = PrivateModuleFragmentDecl::CreateDeserialized(Context, ID); + break; case DECL_OMP_THREADPRIVATE: { Record.skipInts(1); unsigned NumChildren = Record.readInt(); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 6f67acf9a6e7e..d75eebf24a287 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -140,6 +140,7 @@ namespace clang { void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitTopLevelStmtDecl(TopLevelStmtDecl *D); void VisitImportDecl(ImportDecl *D); + void VisitPrivateModuleFragmentDecl(PrivateModuleFragmentDecl *D); void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendDecl(FriendDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); @@ -1829,6 +1830,13 @@ void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) { Record.AddSourceLocation(D->getColonLoc()); Code = serialization::DECL_ACCESS_SPEC; } +void ASTDeclWriter::VisitPrivateModuleFragmentDecl( + PrivateModuleFragmentDecl *D) { + VisitDecl(D); + Record.push_back(Writer.getSubmoduleID(D->getFragment())); + Record.AddSourceLocation(D->getPrivateLoc()); + Code = serialization::DECL_PRIVATE_MODULE_FRAGMENT; +} void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) { VisitDecl(D); diff --git a/clang/test/AST/ast-dump-private-module-fragment.cppm b/clang/test/AST/ast-dump-private-module-fragment.cppm new file mode 100644 index 0000000000000..39b41af403140 --- /dev/null +++ b/clang/test/AST/ast-dump-private-module-fragment.cppm @@ -0,0 +1,12 @@ +//RUN: %clang_cc1 -std=c++20 -ast-dump %s | FileCheck %s + +export module A; + +int inTheInterface(); +// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> {{.*}}inTheInterface 'int ()' + +module :private; +// CHECK: PrivateModuleFragmentDecl 0x{{[0-9a-f]+}} <{{.*}}> + +int inThePrivateFragment(); +// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> {{.*}}inThePrivateFragment 'int ()' diff --git a/clang/test/Modules/mismatched_global_module_state.cppm b/clang/test/Modules/mismatched_global_module_state.cppm new file mode 100644 index 0000000000000..11cfeca5a96b4 --- /dev/null +++ b/clang/test/Modules/mismatched_global_module_state.cppm @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 --std=c++23 -fsyntax-only -verify %s +// see ISSUE 219950 and PR 223044 +module; +module :private; // expected-error {{private module fragment declaration with no preceding module declaration}} +export module Foo; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 2c5e799d12f18..f9a7f7326b70e 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -7299,6 +7299,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::Label: // FIXME: Is this right?? case Decl::CXXDeductionGuide: case Decl::Import: + case Decl::PrivateModuleFragment: case Decl::OMPThreadPrivate: case Decl::OMPGroupPrivate: case Decl::OMPAllocate: _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
