From dd8b5337e9da480640598008de6211dab68c20dc Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 4 Sep 2017 05:37:53 +0000 Subject: [PATCH] Implement Itanium name mangling support for C++ Modules TS. This follows the scheme agreed with Nathan Sidwell, which can be found here: https://gcc.gnu.org/wiki/cxx-modules?action=AttachFile This will be proposed to the itanium-cxx-abi list once we have some experience with how well it works; the ABI for this TS should be considered unstable until it is part of the Itanium C++ ABI. llvm-svn: 312467 --- clang/include/clang/AST/Decl.h | 4 ++ clang/include/clang/AST/DeclBase.h | 2 +- clang/include/clang/Basic/Module.h | 15 +++- clang/include/clang/Lex/ModuleMap.h | 11 ++- clang/lib/AST/Decl.cpp | 26 ++++++- clang/lib/AST/ItaniumMangle.cpp | 69 ++++++++++++++++--- clang/lib/Lex/ModuleMap.cpp | 13 +++- clang/lib/Sema/Sema.cpp | 18 ++++- clang/lib/Sema/SemaDecl.cpp | 20 +++--- clang/lib/Serialization/ASTReader.cpp | 5 +- clang/lib/Serialization/ASTWriter.cpp | 5 +- .../basic/basic.def.odr/p4/module.cpp | 14 ++-- .../basic/basic.def.odr/p4/module.cppm | 29 ++++---- .../basic/basic.def.odr/p4/user.cpp | 2 +- clang/test/CXX/modules-ts/codegen-basics.cppm | 16 ++--- clang/test/SemaCXX/modules-ts.cppm | 12 ++-- 16 files changed, 194 insertions(+), 67 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 18f97ad610f6..b36ab84023ef 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -372,6 +372,10 @@ public: return hasCachedLinkage(); } + /// Get the module that owns this declaration for linkage purposes. + /// There only ever is such a module under the C++ Modules TS. + Module *getOwningModuleForLinkage() const; + /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. NamedDecl *getUnderlyingDecl() { diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 041f0fd484d4..c74879d8e399 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -733,7 +733,7 @@ public: return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned; } - /// Get the module that owns this declaration. + /// Get the module that owns this declaration (for visibility purposes). Module *getOwningModule() const { return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule(); } diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index 177175eae965..edc2f8e72329 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -68,7 +68,11 @@ public: ModuleMapModule, /// \brief This is a C++ Modules TS module interface unit. - ModuleInterfaceUnit + ModuleInterfaceUnit, + + /// \brief This is a fragment of the global module within some C++ Modules + /// TS module. + GlobalModuleFragment, }; /// \brief The kind of this module. @@ -391,6 +395,15 @@ public: return IsFramework && Parent && Parent->isPartOfFramework(); } + /// Set the parent of this module. This should only be used if the parent + /// could not be set during module creation. + void setParent(Module *M) { + assert(!Parent); + Parent = M; + Parent->SubModuleIndex[Name] = Parent->SubModules.size(); + Parent->SubModules.push_back(this); + } + /// \brief Retrieve the full name of this module, including the path from /// its top-level module. /// \param AllowStringLiterals If \c true, components that might not be diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 11506939f9b1..9cca0167518a 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -472,6 +472,14 @@ public: bool IsFramework, bool IsExplicit); + /// \brief Create a 'global module' for a C++ Modules TS module interface + /// unit. + /// + /// We model the global module as a submodule of the module interface unit. + /// Unfortunately, we can't create the module interface unit's Module until + /// later, because we don't know what it will be called. + Module *createGlobalModuleForInterfaceUnit(SourceLocation Loc); + /// \brief Create a new module for a C++ Modules TS module interface unit. /// The module must not already exist, and will be configured for the current /// compilation. @@ -479,7 +487,8 @@ public: /// Note that this also sets the current module to the newly-created module. /// /// \returns The newly-created module. - Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name); + Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name, + Module *GlobalModule); /// \brief Infer the contents of a framework module map from the given /// framework directory. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 2137075138fa..0a4c4a4a7762 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -652,7 +652,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // If the declaration of an identifier for an object has file // scope and no storage-class specifier, its linkage is // external. - LinkageInfo LV; + LinkageInfo LV = getExternalLinkageFor(D); if (!hasExplicitVisibilityAlready(computation)) { if (Optional Vis = getExplicitVisibility(D, computation)) { @@ -1399,6 +1399,30 @@ LinkageInfo LinkageComputer::getDeclLinkageAndVisibility(const NamedDecl *D) { return getLVForDecl(D, usesTypeVisibility(D) ? LVForType : LVForValue); } +Module *NamedDecl::getOwningModuleForLinkage() const { + Module *M = getOwningModule(); + if (!M) + return nullptr; + + switch (M->Kind) { + case Module::ModuleMapModule: + // Module map modules have no special linkage semantics. + return nullptr; + + case Module::ModuleInterfaceUnit: + return M; + + case Module::GlobalModuleFragment: + // External linkage declarations in the global module have no owning module + // for linkage purposes. But internal linkage declarations in the global + // module fragment of a particular module are owned by that module for + // linkage purposes. + return hasExternalFormalLinkage() ? nullptr : M->Parent; + } + + llvm_unreachable("unknown module kind"); +} + void NamedDecl::printName(raw_ostream &os) const { os << Name; } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 294e180b59b2..5372cad29998 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -381,6 +381,7 @@ class CXXNameMangler { AbiTagState AbiTagsRoot; llvm::DenseMap Substitutions; + llvm::DenseMap ModuleSubstitutions; ASTContext &getASTContext() const { return Context.getASTContext(); } @@ -475,6 +476,8 @@ private: void mangleNameWithAbiTags(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags); + void mangleModuleName(const Module *M); + void mangleModuleNamePrefix(StringRef Name); void mangleTemplateName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -845,9 +848,9 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags) { - // ::= - // ::= - // ::= + // ::= [] + // ::= [] + // ::= [] // ::= // const DeclContext *DC = getEffectiveDeclContext(ND); @@ -866,6 +869,19 @@ void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND, DC = IgnoreLinkageSpecDecls(DC); + if (isLocalContainerContext(DC)) { + mangleLocalName(ND, AdditionalAbiTags); + return; + } + + // Do not mangle the owning module for an external linkage declaration. + // This enables backwards-compatibility with non-modular code, and is + // a valid choice since conflicts are not permitted by C++ Modules TS + // [basic.def.odr]/6.2. + if (!ND->hasExternalFormalLinkage()) + if (Module *M = ND->getOwningModuleForLinkage()) + mangleModuleName(M); + if (DC->isTranslationUnit() || isStdNamespace(DC)) { // Check if we have a template. const TemplateArgumentList *TemplateArgs = nullptr; @@ -879,12 +895,42 @@ void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND, return; } - if (isLocalContainerContext(DC)) { - mangleLocalName(ND, AdditionalAbiTags); + mangleNestedName(ND, DC, AdditionalAbiTags); +} + +void CXXNameMangler::mangleModuleName(const Module *M) { + // Implement the C++ Modules TS name mangling proposal; see + // https://gcc.gnu.org/wiki/cxx-modules?action=AttachFile + // + // ::= W + E + // ::= W * E + Out << 'W'; + mangleModuleNamePrefix(M->Name); + Out << 'E'; +} + +void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) { + // ::= _ # 0 < seq-id < 10 + // ::= W _ # otherwise + auto It = ModuleSubstitutions.find(Name); + if (It != ModuleSubstitutions.end()) { + if (It->second < 10) + Out << '_' << static_cast('0' + It->second); + else + Out << 'W' << (It->second - 10) << '_'; return; } - mangleNestedName(ND, DC, AdditionalAbiTags); + // FIXME: Preserve hierarchy in module names rather than flattening + // them to strings; use Module*s as substitution keys. + auto Parts = Name.rsplit('.'); + if (Parts.second.empty()) + Parts.second = Parts.first; + else + mangleModuleNamePrefix(Parts.first); + + Out << Parts.second.size() << Parts.second; + ModuleSubstitutions.insert({Name, ModuleSubstitutions.size()}); } void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD, @@ -1233,13 +1279,16 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, } if (II) { - // We must avoid conflicts between internally- and externally- - // linked variable and function declaration names in the same TU: + // Match GCC's naming convention for internal linkage symbols, for + // symbols that are not actually visible outside of this TU. GCC + // distinguishes between internal and external linkage symbols in + // its mangling, to support cases like this that were valid C++ prior + // to DR426: + // // void test() { extern void foo(); } // static void foo(); - // This naming convention is the same as that followed by GCC, - // though it shouldn't actually matter. if (ND && ND->getFormalLinkage() == InternalLinkage && + !ND->isExternallyVisible() && getEffectiveDeclContext(ND)->isFileContext()) Out << 'L'; diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 40f78ce25ceb..db2f952e3c9d 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -746,8 +746,16 @@ std::pair ModuleMap::findOrCreateModule(StringRef Name, return std::make_pair(Result, true); } +Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) { + auto *Result = new Module("", Loc, nullptr, /*IsFramework*/ false, + /*IsExplicit*/ true, NumCreatedModules++); + Result->Kind = Module::GlobalModuleFragment; + return Result; +} + Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, - StringRef Name) { + StringRef Name, + Module *GlobalModule) { assert(LangOpts.CurrentModule == Name && "module name mismatch"); assert(!Modules[Name] && "redefining existing module"); @@ -757,6 +765,9 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, Result->Kind = Module::ModuleInterfaceUnit; Modules[Name] = SourceModule = Result; + // Reparent the current global module fragment as a submodule of this module. + GlobalModule->setParent(Result); + // Mark the main source file as being within the newly-created module so that // declarations and macros are properly visibility-restricted to it. auto *MainFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index e99e73fc8da2..66cb4976dac7 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -766,10 +766,24 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() { /// declarations. void Sema::ActOnStartOfTranslationUnit() { if (getLangOpts().ModulesTS) { + SourceLocation StartOfTU = + SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); + // We start in the global module; all those declarations are implicitly // module-private (though they do not have module linkage). - Context.getTranslationUnitDecl()->setModuleOwnershipKind( - Decl::ModuleOwnershipKind::ModulePrivate); + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(StartOfTU); + assert(GlobalModule && "module creation should not fail"); + + // Enter the scope of the global module. + ModuleScopes.push_back({}); + ModuleScopes.back().Module = GlobalModule; + VisibleModules.setVisible(GlobalModule, StartOfTU); + + // All declarations created from now on are owned by the global module. + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + TU->setLocalOwningModule(GlobalModule); } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 8334adbbc079..d6de97feb080 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16052,6 +16052,9 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path) { + assert(getLangOpts().ModulesTS && + "should only have module decl in modules TS"); + // A module implementation unit requires that we are not compiling a module // of any kind. A module interface unit requires that we are not compiling a // module map. @@ -16104,10 +16107,10 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, auto &Map = PP.getHeaderSearchInfo().getModuleMap(); Module *Mod; + assert(ModuleScopes.size() == 1 && "expected to be at global module scope"); + switch (MDK) { case ModuleDeclKind::Module: { - // FIXME: Check we're not in a submodule. - // We can't have parsed or imported a definition of this module or parsed a // module map defining it already. if (auto *M = Map.findModule(ModuleName)) { @@ -16121,7 +16124,8 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, } // Create a Module for the module that we're defining. - Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, + ModuleScopes.front().Module); assert(Mod && "module creation should not fail"); break; } @@ -16140,16 +16144,16 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, break; } - // Enter the semantic scope of the module. - ModuleScopes.push_back({}); + // Switch from the global module to the named module. ModuleScopes.back().Module = Mod; - ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); VisibleModules.setVisible(Mod, ModuleLoc); // From now on, we have an owning module for all declarations we see. // However, those declarations are module-private unless explicitly // exported. - Context.getTranslationUnitDecl()->setLocalOwningModule(Mod); + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); + TU->setLocalOwningModule(Mod); // FIXME: Create a ModuleDecl. return nullptr; @@ -16327,7 +16331,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, // C++ Modules TS draft: // An export-declaration shall appear in the purview of a module other than // the global module. - if (ModuleScopes.empty() || !ModuleScopes.back().Module || + if (ModuleScopes.empty() || ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) Diag(ExportLoc, diag::err_export_not_in_module_interface); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 2db46a657096..4ba54fb71278 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4871,7 +4871,6 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); bool First = true; Module *CurrentModule = nullptr; - Module::ModuleKind ModuleKind = Module::ModuleMapModule; RecordData Record; while (true) { llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks(); @@ -4919,6 +4918,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { unsigned Idx = 0; SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]); SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]); + Module::ModuleKind Kind = (Module::ModuleKind)Record[Idx++]; bool IsFramework = Record[Idx++]; bool IsExplicit = Record[Idx++]; bool IsSystem = Record[Idx++]; @@ -4965,7 +4965,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { CurrentModule->PresumedModuleMapFile = F.ModuleMapPath; } - CurrentModule->Kind = ModuleKind; + CurrentModule->Kind = Kind; CurrentModule->Signature = F.Signature; CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; @@ -5064,7 +5064,6 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules); } - ModuleKind = (Module::ModuleKind)Record[2]; break; } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 0d45b27cbe67..9adade5250ce 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -2716,6 +2716,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Kind Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem @@ -2793,8 +2794,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { // Write the submodule metadata block. RecordData::value_type Record[] = { getNumberOfModules(WritingModule), - FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS, - (unsigned)WritingModule->Kind}; + FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS}; Stream.EmitRecord(SUBMODULE_METADATA, Record); // Write all of the submodules. @@ -2816,6 +2816,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { RecordData::value_type Record[] = {SUBMODULE_DEFINITION, ID, ParentID, + Mod->Kind, Mod->IsFramework, Mod->IsExplicit, Mod->IsSystem, diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp index dc6a3635a8ee..83cad5cc9b27 100644 --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp +++ b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp @@ -4,15 +4,15 @@ // CHECK-DAG: @extern_var_exported = external global // FIXME: Should this be 'external global'? // CHECK-DAG: @inline_var_exported = linkonce_odr global -// CHECK-DAG: @_ZL19static_var_exported = external global +// CHECK-DAG: @_ZW6ModuleE19static_var_exported = external global // CHECK-DAG: @const_var_exported = external constant // // FIXME: The module name should be mangled into all of these. // CHECK-DAG: @extern_var_module_linkage = external global // FIXME: Should this be 'external global'? // CHECK-DAG: @inline_var_module_linkage = linkonce_odr global -// CHECK-DAG: @_ZL25static_var_module_linkage = external global -// CHECK-DAG: @_ZL24const_var_module_linkage = external constant +// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = external global +// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = external constant module Module; @@ -28,15 +28,13 @@ void use() { (void)&const_var_exported; // FIXME: This symbol should not be visible here. - // CHECK: declare {{.*}}@_ZL26used_static_module_linkagev + // CHECK: declare {{.*}}@_ZW6ModuleE26used_static_module_linkagev used_static_module_linkage(); - // FIXME: The module name should be mangled into the name of this function. - // CHECK: define linkonce_odr {{.*}}@_Z26used_inline_module_linkagev + // CHECK: define linkonce_odr {{.*}}@_ZW6ModuleE26used_inline_module_linkagev used_inline_module_linkage(); - // FIXME: The module name should be mangled into the name of this function. - // CHECK: declare {{.*}}@_Z24noninline_module_linkagev + // CHECK: declare {{.*}}@_ZW6ModuleE24noninline_module_linkagev noninline_module_linkage(); (void)&extern_var_module_linkage; diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm index d452f741a0fb..093ce235a75a 100644 --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm +++ b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm @@ -11,7 +11,7 @@ // can discard this global and its initializer (if any), and other TUs are not // permitted to run the initializer for this variable. // CHECK-DAG: @inline_var_exported = linkonce_odr global -// CHECK-DAG: @_ZL19static_var_exported = global +// CHECK-DAG: @_ZW6ModuleE19static_var_exported = global // CHECK-DAG: @const_var_exported = constant // // FIXME: The module name should be mangled into all of these. @@ -20,8 +20,8 @@ // can discard this global and its initializer (if any), and other TUs are not // permitted to run the initializer for this variable. // CHECK-DAG: @inline_var_module_linkage = linkonce_odr global -// CHECK-DAG: @_ZL25static_var_module_linkage = global -// CHECK-DAG: @_ZL24const_var_module_linkage = constant +// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = global +// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = constant static void unused_static_global_module() {} static void used_static_global_module() {} @@ -57,9 +57,9 @@ export module Module; export { // FIXME: These should be ill-formed: you can't export an internal linkage // symbol, per [dcl.module.interface]p2. - // CHECK: define void {{.*}}@_ZL22unused_static_exportedv + // CHECK: define void {{.*}}@_ZW6ModuleE22unused_static_exportedv static void unused_static_exported() {} - // CHECK: define void {{.*}}@_ZL20used_static_exportedv + // CHECK: define void {{.*}}@_ZW6ModuleE20used_static_exportedv static void used_static_exported() {} inline void unused_inline_exported() {} @@ -88,11 +88,9 @@ export { // FIXME: Ideally we wouldn't emit this as its name is not visible outside this // TU, but this module interface might contain a template that can use this // function so we conservatively emit it for now. -// FIXME: The module name should be mangled into the name of this function. -// CHECK: define void {{.*}}@_ZL28unused_static_module_linkagev +// CHECK: define void {{.*}}@_ZW6ModuleE28unused_static_module_linkagev static void unused_static_module_linkage() {} -// FIXME: The module name should be mangled into the name of this function. -// CHECK: define void {{.*}}@_ZL26used_static_module_linkagev +// CHECK: define void {{.*}}@_ZW6ModuleE26used_static_module_linkagev static void used_static_module_linkage() {} inline void unused_inline_module_linkage() {} @@ -103,12 +101,10 @@ inline int inline_var_module_linkage; static int static_var_module_linkage; const int const_var_module_linkage = 3; -// FIXME: The module name should be mangled into the name of this function. -// CHECK: define void {{.*}}@_Z24noninline_module_linkagev +// CHECK: define void {{.*}}@_ZW6ModuleE24noninline_module_linkagev void noninline_module_linkage() { used_static_module_linkage(); - // FIXME: The module name should be mangled into the name of this function. - // CHECK: define linkonce_odr {{.*}}@_Z26used_inline_module_linkagev + // CHECK: define linkonce_odr {{.*}}@_ZW6ModuleE26used_inline_module_linkagev used_inline_module_linkage(); (void)&extern_var_module_linkage; @@ -116,3 +112,10 @@ void noninline_module_linkage() { (void)&static_var_module_linkage; (void)&const_var_module_linkage; } + +struct a { + struct b {}; + struct c {}; +}; +// CHECK: define void @_ZW6ModuleE1fW_0EN1a1bEW_0ENS_1cE( +void f(a::b, a::c) {} diff --git a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp index f6e0238c6b4b..ccbf222658cd 100644 --- a/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp +++ b/clang/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp @@ -5,7 +5,7 @@ // FIXME: Should this be 'external global'? // CHECK-DAG: @inline_var_exported = linkonce_odr global // FIXME: These should be 'extern global' and 'extern constant'. -// CHECK-DAG: @_ZL19static_var_exported = global +// CHECK-DAG: @_ZW6ModuleE19static_var_exported = global // CHECK-DAG: @const_var_exported = constant import Module; diff --git a/clang/test/CXX/modules-ts/codegen-basics.cppm b/clang/test/CXX/modules-ts/codegen-basics.cppm index d1552d9edd26..a85e12df26f6 100644 --- a/clang/test/CXX/modules-ts/codegen-basics.cppm +++ b/clang/test/CXX/modules-ts/codegen-basics.cppm @@ -4,20 +4,18 @@ export module FooBar; export { - // CHECK-LABEL: define i32 @_Z1fv( + // CHECK-DAG: define i32 @_Z1fv( int f() { return 0; } } -// CHECK-LABEL: define weak_odr void @_Z2f2v( +// CHECK-DAG: define weak_odr void @_ZW6FooBarE2f2v( inline void f2() { } +// CHECK-DAG: define void @_ZW6FooBarE2f3v( +static void f3() {} +export void use_f3() { f3(); } + // FIXME: Emit global variables and their initializers with this TU. -// Emit an initialization function that other TUs can call, with guard variable. - -// FIXME: Mangle non-exported symbols so they don't collide with -// non-exported symbols from other modules? - -// FIXME: Formally-internal-linkage symbols that are used from an exported -// symbol need a mangled name and external linkage. +// Emit an initialization function that other TUs can call, with guard variable? // FIXME: const-qualified variables don't have implicit internal linkage when owned by a module. diff --git a/clang/test/SemaCXX/modules-ts.cppm b/clang/test/SemaCXX/modules-ts.cppm index 2ea4958bffda..065818c562af 100644 --- a/clang/test/SemaCXX/modules-ts.cppm +++ b/clang/test/SemaCXX/modules-ts.cppm @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DTEST=0 -// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DTEST=1 -// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -verify -DTEST=2 -// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -verify -Dfoo=bar -DTEST=3 +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.0.pcm -verify -DTEST=0 +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.1.pcm -verify -DTEST=1 +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.0.pcm -o %t.2.pcm -verify -DTEST=2 +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.0.pcm -o %t.3.pcm -verify -Dfoo=bar -DTEST=3 #if TEST == 0 // expected-no-diagnostics @@ -21,7 +21,7 @@ static int m; // expected-note-re@modules-ts.cppm:1 {{'{{.*}}modules-ts.cppm' included multiple times, additional include site in header from module 'foo'}} #endif int n; -#if TEST >= 2 +#if TEST == 2 // expected-error@-2 {{redefinition of '}} // expected-note@-3 {{unguarded header; consider using #ifdef guards or #pragma once}} // FIXME: We should drop the "header from" in this diagnostic. @@ -60,7 +60,7 @@ int use_b = b; int use_n = n; // FIXME: this should not be visible, because it is not exported extern int n; -static_assert(&n == p); // FIXME: these are not the same entity +static_assert(&n != p); #endif