Author: rsmith Date: Thu Apr 18 14:12:54 2019 New Revision: 358713 URL: http://llvm.org/viewvc/llvm-project?rev=358713&view=rev Log: [c++2a] Add semantic support for private module fragments.
Added: cfe/trunk/test/CXX/basic/basic.link/p2.cpp cfe/trunk/test/CXX/module/module.interface/ cfe/trunk/test/CXX/module/module.interface/p1.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Basic/Module.h cfe/trunk/include/clang/Lex/ModuleMap.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/Lex/ModuleMap.cpp cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaModule.cpp cfe/trunk/test/CXX/basic/basic.link/p1.cpp cfe/trunk/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Apr 18 14:12:54 2019 @@ -9276,8 +9276,20 @@ def note_global_module_introducer_missin def err_export_within_export : Error< "export declaration appears within another export declaration">; def err_export_not_in_module_interface : Error< - "export declaration can only be used within a module interface unit after " - "the module declaration">; + "export declaration can only be used within a module interface unit" + "%select{ after the module declaration|}0">; +def err_export_in_private_module_fragment : Error< + "export declaration cannot be used in a private module fragment">; +def note_private_module_fragment : Note< + "private module fragment begins here">; +def err_private_module_fragment_not_module : Error< + "private module fragment declaration with no preceding module declaration">; +def err_private_module_fragment_redefined : Error< + "private module fragment redefined">; +def err_private_module_fragment_not_module_interface : Error< + "private module fragment in module implementation unit">; +def note_not_module_interface_add_export : Note< + "add 'export' here if this is intended to be a module interface unit">; def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn< "ambiguous use of internal linkage declaration %0 defined in multiple modules">, Modified: cfe/trunk/include/clang/Basic/Module.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Module.h (original) +++ cfe/trunk/include/clang/Basic/Module.h Thu Apr 18 14:12:54 2019 @@ -77,9 +77,11 @@ public: /// This is a C++ Modules TS module interface unit. ModuleInterfaceUnit, - /// This is a fragment of the global module within some C++ Modules - /// TS module. + /// This is a fragment of the global module within some C++ module. GlobalModuleFragment, + + /// This is the private module fragment within some C++ module. + PrivateModuleFragment, }; /// The kind of this module. @@ -111,6 +113,11 @@ public: /// eventually be exposed, for use in "private" modules. std::string ExportAsModule; + /// Does this Module scope describe part of the purview of a named C++ module? + bool isModulePurview() const { + return Kind == ModuleInterfaceUnit || Kind == PrivateModuleFragment; + } + private: /// The submodules of this module, indexed by name. std::vector<Module *> SubModules; Modified: cfe/trunk/include/clang/Lex/ModuleMap.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/include/clang/Lex/ModuleMap.h (original) +++ cfe/trunk/include/clang/Lex/ModuleMap.h Thu Apr 18 14:12:54 2019 @@ -520,14 +520,18 @@ public: bool IsFramework, bool IsExplicit); - /// Create a 'global module' for a C++ Modules TS module interface unit. + /// Create a global module fragment for a C++ module 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); + /// We model the global module fragment 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 *createGlobalModuleFragmentForModuleUnit(SourceLocation Loc); - /// Create a new module for a C++ Modules TS module interface unit. + /// Create a global module fragment for a C++ module interface unit. + Module *createPrivateModuleFragmentForInterfaceUnit(Module *Parent, + SourceLocation Loc); + + /// Create a new module for a C++ module interface unit. /// The module must not already exist, and will be configured for the current /// compilation. /// Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Apr 18 14:12:54 2019 @@ -1386,8 +1386,21 @@ public: void emitAndClearUnusedLocalTypedefWarnings(); + enum TUFragmentKind { + /// The global module fragment, between 'module;' and a module-declaration. + Global, + /// A normal translation unit fragment. For a non-module unit, this is the + /// entire translation unit. Otherwise, it runs from the module-declaration + /// to the private-module-fragment (if any) or the end of the TU (if not). + Normal, + /// The private module fragment, between 'module :private;' and the end of + /// the translation unit. + Private + }; + void ActOnStartOfTranslationUnit(); void ActOnEndOfTranslationUnit(); + void ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind); void CheckDelegatingCtorCycles(); @@ -2180,10 +2193,7 @@ public: /// \param ModuleLoc The location of the 'module' keyword. /// \param PrivateLoc The location of the 'private' keyword. DeclGroupPtrTy ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, - SourceLocation PrivateLoc) { - // FIXME - return DeclGroupPtrTy(); - } + SourceLocation PrivateLoc); /// The parser has processed a module import declaration. /// Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Thu Apr 18 14:12:54 2019 @@ -567,6 +567,13 @@ static bool isSingleLineLanguageLinkage( return false; } +/// Determine whether D is declared in the purview of a named module. +static bool isInModulePurview(const NamedDecl *D) { + if (auto *M = D->getOwningModule()) + return M->isModulePurview(); + return false; +} + static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { // FIXME: Handle isModulePrivate. switch (D->getModuleOwnershipKind()) { @@ -575,8 +582,7 @@ static bool isExportedFromModuleInteface return false; case Decl::ModuleOwnershipKind::Visible: case Decl::ModuleOwnershipKind::VisibleWhenImported: - if (auto *M = D->getOwningModule()) - return M->Kind == Module::ModuleInterfaceUnit; + return isInModulePurview(D); } llvm_unreachable("unexpected module ownership kind"); } @@ -586,9 +592,8 @@ static LinkageInfo getInternalLinkageFor // as "module-internal linkage", which means that they have internal linkage // formally but can be indirectly accessed from outside the module via inline // functions and templates defined within the module. - if (auto *M = D->getOwningModule()) - if (M->Kind == Module::ModuleInterfaceUnit) - return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); + if (isInModulePurview(D)) + return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); return LinkageInfo::internal(); } @@ -598,11 +603,9 @@ static LinkageInfo getExternalLinkageFor // - A name declared at namespace scope that does not have internal linkage // by the previous rules and that is introduced by a non-exported // declaration has module linkage. - if (auto *M = D->getOwningModule()) - if (M->Kind == Module::ModuleInterfaceUnit) - if (!isExportedFromModuleIntefaceUnit( - cast<NamedDecl>(D->getCanonicalDecl()))) - return LinkageInfo(ModuleLinkage, DefaultVisibility, false); + if (isInModulePurview(D) && + !isExportedFromModuleIntefaceUnit(cast<NamedDecl>(D->getCanonicalDecl()))) + return LinkageInfo(ModuleLinkage, DefaultVisibility, false); return LinkageInfo::external(); } @@ -1507,6 +1510,11 @@ Module *Decl::getOwningModuleForLinkage( } return InternalLinkage ? M->Parent : nullptr; } + + case Module::PrivateModuleFragment: + // The private module fragment is part of its containing module for linkage + // purposes. + return M->Parent; } llvm_unreachable("unknown module kind"); Modified: cfe/trunk/lib/Lex/ModuleMap.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/lib/Lex/ModuleMap.cpp (original) +++ cfe/trunk/lib/Lex/ModuleMap.cpp Thu Apr 18 14:12:54 2019 @@ -806,7 +806,7 @@ std::pair<Module *, bool> ModuleMap::fin return std::make_pair(Result, true); } -Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) { +Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc) { PendingSubmodules.emplace_back( new Module("<global>", Loc, nullptr, /*IsFramework*/ false, /*IsExplicit*/ true, NumCreatedModules++)); @@ -814,6 +814,16 @@ Module *ModuleMap::createGlobalModuleFor return PendingSubmodules.back().get(); } +Module * +ModuleMap::createPrivateModuleFragmentForInterfaceUnit(Module *Parent, + SourceLocation Loc) { + auto *Result = + new Module("<private>", Loc, Parent, /*IsFramework*/ false, + /*IsExplicit*/ true, NumCreatedModules++); + Result->Kind = Module::PrivateModuleFragment; + return Result; +} + Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name, Module *GlobalModule) { Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Thu Apr 18 14:12:54 2019 @@ -857,20 +857,13 @@ void Sema::ActOnStartOfTranslationUnit() } } -/// ActOnEndOfTranslationUnit - This is called at the very end of the -/// translation unit when EOF is reached and all but the top-level scope is -/// popped. -void Sema::ActOnEndOfTranslationUnit() { - assert(DelayedDiagnostics.getCurrentPool() == nullptr - && "reached end of translation unit with a pool attached?"); - - // If code completion is enabled, don't perform any end-of-translation-unit - // work. - if (PP.isCodeCompletionEnabled()) +void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { + // No explicit actions are required at the end of the global module fragment. + if (Kind == TUFragmentKind::Global) return; // Transfer late parsed template instantiations over to the pending template - // instantiation list. During normal compliation, the late template parser + // instantiation list. During normal compilation, the late template parser // will be installed and instantiating these templates will succeed. // // If we are building a TU prefix for serialization, it is also safe to @@ -883,50 +876,79 @@ void Sema::ActOnEndOfTranslationUnit() { LateParsedInstantiations.end()); LateParsedInstantiations.clear(); + // If DefinedUsedVTables ends up marking any virtual member functions it + // might lead to more pending template instantiations, which we then need + // to instantiate. + DefineUsedVTables(); + + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not + // carefully keep track of the point of instantiation (C++ [temp.point]). + // This means that name lookup that occurs within the template + // instantiation will always happen at the end of the translation unit, + // so it will find some names that are not required to be found. This is + // valid, but we could do better by diagnosing if an instantiation uses a + // name that was not visible at its first point of instantiation. + if (ExternalSource) { + // Load pending instantiations from the external source. + SmallVector<PendingImplicitInstantiation, 4> Pending; + ExternalSource->ReadPendingInstantiations(Pending); + for (auto PII : Pending) + if (auto Func = dyn_cast<FunctionDecl>(PII.first)) + Func->setInstantiationIsPending(true); + PendingInstantiations.insert(PendingInstantiations.begin(), + Pending.begin(), Pending.end()); + } + + { + llvm::TimeTraceScope TimeScope("PerformPendingInstantiations", + StringRef("")); + PerformPendingInstantiations(); + } + + assert(LateParsedInstantiations.empty() && + "end of TU template instantiation should not create more " + "late-parsed templates"); +} + +/// ActOnEndOfTranslationUnit - This is called at the very end of the +/// translation unit when EOF is reached and all but the top-level scope is +/// popped. +void Sema::ActOnEndOfTranslationUnit() { + assert(DelayedDiagnostics.getCurrentPool() == nullptr + && "reached end of translation unit with a pool attached?"); + + // If code completion is enabled, don't perform any end-of-translation-unit + // work. + if (PP.isCodeCompletionEnabled()) + return; + // Complete translation units and modules define vtables and perform implicit // instantiations. PCH files do not. if (TUKind != TU_Prefix) { DiagnoseUseOfUnimplementedSelectors(); - // If DefinedUsedVTables ends up marking any virtual member functions it - // might lead to more pending template instantiations, which we then need - // to instantiate. - DefineUsedVTables(); - - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not - // carefully keep track of the point of instantiation (C++ [temp.point]). - // This means that name lookup that occurs within the template - // instantiation will always happen at the end of the translation unit, - // so it will find some names that are not required to be found. This is - // valid, but we could do better by diagnosing if an instantiation uses a - // name that was not visible at its first point of instantiation. - if (ExternalSource) { - // Load pending instantiations from the external source. - SmallVector<PendingImplicitInstantiation, 4> Pending; - ExternalSource->ReadPendingInstantiations(Pending); - for (auto PII : Pending) - if (auto Func = dyn_cast<FunctionDecl>(PII.first)) - Func->setInstantiationIsPending(true); - PendingInstantiations.insert(PendingInstantiations.begin(), - Pending.begin(), Pending.end()); - } - - { - llvm::TimeTraceScope TimeScope("PerformPendingInstantiations", - StringRef("")); - PerformPendingInstantiations(); - } - - assert(LateParsedInstantiations.empty() && - "end of TU template instantiation should not create more " - "late-parsed templates"); + ActOnEndOfTranslationUnitFragment( + !ModuleScopes.empty() && ModuleScopes.back().Module->Kind == + Module::PrivateModuleFragment + ? TUFragmentKind::Private + : TUFragmentKind::Normal); if (LateTemplateParserCleanup) LateTemplateParserCleanup(OpaqueParser); CheckDelayedMemberExceptionSpecs(); + } else { + // If we are building a TU prefix for serialization, it is safe to transfer + // these over, even though they are not parsed. The end of the TU should be + // outside of any eager template instantiation scope, so when this AST is + // deserialized, these templates will not be parsed until the end of the + // combined TU. + PendingInstantiations.insert(PendingInstantiations.end(), + LateParsedInstantiations.begin(), + LateParsedInstantiations.end()); + LateParsedInstantiations.clear(); } DiagnoseUnterminatedPragmaPack(); @@ -1000,7 +1022,7 @@ void Sema::ActOnEndOfTranslationUnit() { if (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface && (ModuleScopes.empty() || - ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) && + !ModuleScopes.back().Module->isModulePurview()) && !DiagnosedMissingModuleDeclaration) { // FIXME: Make a better guess as to where to put the module declaration. Diag(getSourceManager().getLocForStartOfFile( Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Apr 18 14:12:54 2019 @@ -1461,12 +1461,17 @@ bool Sema::CheckRedeclarationModuleOwner Module *NewM = New->getOwningModule(); Module *OldM = Old->getOwningModule(); + + if (NewM && NewM->Kind == Module::PrivateModuleFragment) + NewM = NewM->Parent; + if (OldM && OldM->Kind == Module::PrivateModuleFragment) + OldM = OldM->Parent; + if (NewM == OldM) return false; - // FIXME: Check proclaimed-ownership-declarations here too. - bool NewIsModuleInterface = NewM && NewM->Kind == Module::ModuleInterfaceUnit; - bool OldIsModuleInterface = OldM && OldM->Kind == Module::ModuleInterfaceUnit; + bool NewIsModuleInterface = NewM && NewM->isModulePurview(); + bool OldIsModuleInterface = OldM && OldM->isModulePurview(); if (NewIsModuleInterface || OldIsModuleInterface) { // C++ Modules TS [basic.def.odr] 6.2/6.7 [sic]: // if a declaration of D [...] appears in the purview of a module, all Modified: cfe/trunk/lib/Sema/SemaModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaModule.cpp?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaModule.cpp (original) +++ cfe/trunk/lib/Sema/SemaModule.cpp Thu Apr 18 14:12:54 2019 @@ -69,7 +69,7 @@ Sema::ActOnGlobalModuleFragmentDecl(Sour // We start in the global module; all those declarations are implicitly // module-private (though they do not have module linkage). auto &Map = PP.getHeaderSearchInfo().getModuleMap(); - auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(ModuleLoc); + auto *GlobalModule = Map.createGlobalModuleFragmentForModuleUnit(ModuleLoc); assert(GlobalModule && "module creation should not fail"); // Enter the scope of the global module. @@ -128,7 +128,7 @@ Sema::ActOnModuleDecl(SourceLocation Sta // Only one module-declaration is permitted per source file. if (!ModuleScopes.empty() && - ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) { + ModuleScopes.back().Module->isModulePurview()) { Diag(ModuleLoc, diag::err_module_redeclaration); Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module), diag::note_prev_module_declaration); @@ -220,6 +220,9 @@ Sema::ActOnModuleDecl(SourceLocation Sta ModuleScopes.push_back({}); if (getLangOpts().ModulesLocalVisibility) ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); + } else { + // We're done with the global module fragment now. + ActOnEndOfTranslationUnitFragment(TUFragmentKind::Global); } // Switch from the global module fragment (if any) to the named module. @@ -239,6 +242,68 @@ Sema::ActOnModuleDecl(SourceLocation Sta return nullptr; } +Sema::DeclGroupPtrTy +Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, + SourceLocation PrivateLoc) { + // C++20 [basic.link]/2: + // A private-module-fragment shall appear only in a primary module + // interface unit. + switch (ModuleScopes.empty() ? Module::GlobalModuleFragment + : ModuleScopes.back().Module->Kind) { + case Module::ModuleMapModule: + case Module::GlobalModuleFragment: + Diag(PrivateLoc, diag::err_private_module_fragment_not_module); + return nullptr; + + case Module::PrivateModuleFragment: + Diag(PrivateLoc, diag::err_private_module_fragment_redefined); + Diag(ModuleScopes.back().BeginLoc, diag::note_previous_definition); + return nullptr; + + case Module::ModuleInterfaceUnit: + break; + } + + if (!ModuleScopes.back().ModuleInterface) { + Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface); + Diag(ModuleScopes.back().BeginLoc, + diag::note_not_module_interface_add_export) + << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); + return nullptr; + } + + // FIXME: Check this isn't a module interface partition. + // FIXME: Check that this translation unit does not import any partitions; + // such imports would violate [basic.link]/2's "shall be the only module unit" + // restriction. + + // We've finished the public fragment of the translation unit. + ActOnEndOfTranslationUnitFragment(TUFragmentKind::Normal); + + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + Module *PrivateModuleFragment = + Map.createPrivateModuleFragmentForInterfaceUnit( + ModuleScopes.back().Module, PrivateLoc); + assert(PrivateModuleFragment && "module creation should not fail"); + + // Enter the scope of the private module fragment. + ModuleScopes.push_back({}); + ModuleScopes.back().BeginLoc = ModuleLoc; + ModuleScopes.back().Module = PrivateModuleFragment; + ModuleScopes.back().ModuleInterface = true; + VisibleModules.setVisible(PrivateModuleFragment, ModuleLoc); + + // All declarations created from now on are scoped to the private module + // fragment (and are neither visible nor reachable in importers of the module + // interface). + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); + TU->setLocalOwningModule(PrivateModuleFragment); + + // FIXME: Consider creating an explicit representation of this declaration. + return nullptr; +} + DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, @@ -451,17 +516,26 @@ Decl *Sema::ActOnStartExportDecl(Scope * SourceLocation LBraceLoc) { ExportDecl *D = ExportDecl::Create(Context, CurContext, 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().ModuleInterface) - Diag(ExportLoc, diag::err_export_not_in_module_interface); + // C++20 [module.interface]p1: + // An export-declaration shall appear only [...] in the purview of a module + // interface unit. An export-declaration shall not appear directly or + // indirectly within an unnamed namespace or a private-module-fragment. + // FIXME: Check for the unnamed namespace case. + if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) { + Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; + } else if (!ModuleScopes.back().ModuleInterface) { + Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1; + Diag(ModuleScopes.back().BeginLoc, + diag::note_not_module_interface_add_export) + << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); + } else if (ModuleScopes.back().Module->Kind == + Module::PrivateModuleFragment) { + Diag(ExportLoc, diag::err_export_in_private_module_fragment); + Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment); + } - // An export-declaration [...] shall not contain more than one - // export keyword. - // - // The intent here is that an export-declaration cannot appear within another - // export-declaration. + // [...] its declaration or declaration-seq shall not contain an + // export-declaration. if (D->isExported()) Diag(ExportLoc, diag::err_export_within_export); Modified: cfe/trunk/test/CXX/basic/basic.link/p1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.link/p1.cpp?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/test/CXX/basic/basic.link/p1.cpp (original) +++ cfe/trunk/test/CXX/basic/basic.link/p1.cpp Thu Apr 18 14:12:54 2019 @@ -1,24 +1,31 @@ // RUN: %clang_cc1 -std=c++2a -verify %s // RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG %s // RUN: %clang_cc1 -std=c++2a -verify -DNO_MODULE_DECL %s +// RUN: %clang_cc1 -std=c++2a -verify -DNO_PRIVATE_FRAG %s +// RUN: %clang_cc1 -std=c++2a -verify -DNO_MODULE_DECL -DNO_PRIVATE_FRAG %s +// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_PRIVATE_FRAG %s +// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_MODULE_DECL %s +// RUN: %clang_cc1 -std=c++2a -verify -DNO_GLOBAL_FRAG -DNO_MODULE_DECL -DNO_PRIVATE_FRAG %s // RUN: %clang_cc1 -std=c++2a -verify -DEXPORT_FRAGS %s -#ifdef NO_GLOBAL_FRAG -// expected-error@#mod-decl {{module declaration must occur at the start of the translation unit}} -// expected-note@1 {{add 'module;' to the start of the file to introduce a global module fragment}} -#else +#ifndef NO_GLOBAL_FRAG #ifdef EXPORT_FRAGS export // expected-error {{global module fragment cannot be exported}} #endif -module; // #glob-frag +module; +#ifdef NO_MODULE_DECL +// expected-error@-2 {{missing 'module' declaration at end of global module fragment introduced here}} +#endif #endif extern int a; // #a1 -#ifdef NO_MODULE_DECL -// expected-error@#glob-frag {{missing 'module' declaration at end of global module fragment introduced here}} -#else -export module Foo; // #mod-decl +#ifndef NO_MODULE_DECL +export module Foo; +#ifdef NO_GLOBAL_FRAG +// expected-error@-2 {{module declaration must occur at the start of the translation unit}} +// expected-note@1 {{add 'module;' to the start of the file to introduce a global module fragment}} +#endif // expected-error@#a2 {{declaration of 'a' in module Foo follows declaration in the global module}} // expected-note@#a1 {{previous decl}} @@ -29,9 +36,22 @@ extern int b; module; // expected-error {{'module;' introducing a global module fragment can appear only at the start of the translation unit}} +#ifndef NO_PRIVATE_FRAG #ifdef EXPORT_FRAGS export // expected-error {{private module fragment cannot be exported}} #endif -module :private; +module :private; // #priv-frag +#ifdef NO_MODULE_DECL +// expected-error@-2 {{private module fragment declaration with no preceding module declaration}} +#endif +#endif int b; // ok + + +#ifndef NO_PRIVATE_FRAG +#ifndef NO_MODULE_DECL +module :private; // expected-error {{private module fragment redefined}} +// expected-note@#priv-frag {{previous definition is here}} +#endif +#endif Added: cfe/trunk/test/CXX/basic/basic.link/p2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.link/p2.cpp?rev=358713&view=auto ============================================================================== --- cfe/trunk/test/CXX/basic/basic.link/p2.cpp (added) +++ cfe/trunk/test/CXX/basic/basic.link/p2.cpp Thu Apr 18 14:12:54 2019 @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++2a -DEXPORT %s -verify +// RUN: %clang_cc1 -std=c++2a -DEXPORT %s -emit-module-interface -o %t.pcm +// RUN: %clang_cc1 -std=c++2a -UEXPORT %s -verify -fmodule-file=%t.pcm + +#ifdef EXPORT +// expected-no-diagnostics +export +#else +// expected-note@+2 {{add 'export' here}} +#endif +module M; + +#ifndef EXPORT +// expected-error@+2 {{private module fragment in module implementation unit}} +#endif +module :private; Added: cfe/trunk/test/CXX/module/module.interface/p1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/module/module.interface/p1.cpp?rev=358713&view=auto ============================================================================== --- cfe/trunk/test/CXX/module/module.interface/p1.cpp (added) +++ cfe/trunk/test/CXX/module/module.interface/p1.cpp Thu Apr 18 14:12:54 2019 @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -std=c++2a %s -DERRORS -verify +// RUN: %clang_cc1 -std=c++2a %s -emit-module-interface -o %t.pcm +// RUN: %clang_cc1 -std=c++2a %s -fmodule-file=%t.pcm -DIMPLEMENTATION -verify -Db=b2 -Dc=c2 + +module; + +#ifdef ERRORS +export int a; // expected-error {{after the module declaration}} +#endif + +#ifndef IMPLEMENTATION +export +#else +// expected-error@#1 {{can only be used within a module interface unit}} +// expected-error@#2 {{can only be used within a module interface unit}} +// expected-note@+2 1+{{add 'export'}} +#endif +module M; + +export int b; // #1 +namespace N { + export int c; // #2 +} + +#ifdef ERRORS +namespace { + export int d1; // FIXME: invalid + namespace X { + export int d2; // FIXME: invalid + } +} + +export export int e; // expected-error {{within another export declaration}} +export { export int f; } // expected-error {{within another export declaration}} + +module :private; // expected-note {{private module fragment begins here}} +export int priv; // expected-error {{export declaration cannot be used in a private module fragment}} +#endif Modified: cfe/trunk/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp?rev=358713&r1=358712&r2=358713&view=diff ============================================================================== --- cfe/trunk/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp (original) +++ cfe/trunk/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp Thu Apr 18 14:12:54 2019 @@ -10,7 +10,7 @@ // expected-no-diagnostics export module A; #elif IMPLEMENTATION -module A; +module A; // #module-decl #ifdef BUILT_AS_INTERFACE // expected-error@-2 {{missing 'export' specifier in module declaration while building module interface}} #define INTERFACE @@ -23,6 +23,9 @@ module A; #ifndef INTERFACE export int b; // expected-error {{export declaration can only be used within a module interface unit}} +#ifdef IMPLEMENTATION +// expected-note@#module-decl {{add 'export' here}} +#endif #else export int a; #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits