diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-04-14 08:06:59 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-04-14 08:06:59 +0000 |
| commit | d652bdd05f1c6a7f732fc01009ce68f7190d0e3d (patch) | |
| tree | a803f9072874de1deca5bcc531ce1dbad1d2f11a /clang/lib | |
| parent | de20429cfc00f8d962c41a42024e8309bdda29ed (diff) | |
| download | bcm5719-llvm-d652bdd05f1c6a7f732fc01009ce68f7190d0e3d.tar.gz bcm5719-llvm-d652bdd05f1c6a7f732fc01009ce68f7190d0e3d.zip | |
[c++20] Parsing support for module-declarations, import-declarations,
and the global and private module fragment.
For now, the private module fragment introducer is ignored, but use of
the global module fragment introducer should be properly enforced.
llvm-svn: 358353
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Lex/PPDirectives.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Parse/Parser.cpp | 202 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.cpp | 32 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 121 |
5 files changed, 298 insertions, 62 deletions
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index c4adec83fb1..b3778c1d6f8 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1648,6 +1648,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, EndLoc, LookupFrom, LookupFromFile); switch (Action.Kind) { case ImportAction::None: + case ImportAction::SkippedModuleImport: break; case ImportAction::ModuleBegin: EnterAnnotationToken(SourceRange(HashLoc, EndLoc), @@ -2034,6 +2035,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( switch (Action) { case Skip: // If we don't need to enter the file, stop now. + if (Module *M = SuggestedModule.getModule()) + return {ImportAction::SkippedModuleImport, M}; return {ImportAction::None}; case IncludeLimitReached: @@ -2117,6 +2120,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( return {ImportAction::ModuleBegin, M}; } + assert(!IsImportDecl && "failed to diagnose missing module for import decl"); return {ImportAction::None}; } diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 48d4a62ab7d..ebd4ae07ba4 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -1168,6 +1168,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) { LLVM_FALLTHROUGH; case ImportAction::ModuleImport: + case ImportAction::SkippedModuleImport: // We chose to import (or textually enter) the file. Convert the // header-name token into a header unit annotation token. Suffix[0].setKind(tok::annot_header_unit); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index b477e1f8bbc..d1920a9ae7a 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -460,6 +460,8 @@ void Parser::Initialize() { Ident_sealed = nullptr; Ident_override = nullptr; Ident_GNU_final = nullptr; + Ident_import = nullptr; + Ident_module = nullptr; Ident_super = &PP.getIdentifierTable().get("super"); @@ -512,6 +514,11 @@ void Parser::Initialize() { PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block); } + if (getLangOpts().CPlusPlusModules) { + Ident_import = PP.getIdentifierInfo("import"); + Ident_module = PP.getIdentifierInfo("module"); + } + Actions.Initialize(); // Prime the lexer look-ahead. @@ -525,6 +532,16 @@ void Parser::LateTemplateParserCleanupCallback(void *P) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds); } +/// Parse the first top-level declaration in a translation unit. +/// +/// translation-unit: +/// [C] external-declaration +/// [C] translation-unit external-declaration +/// [C++] top-level-declaration-seq[opt] +/// [C++20] global-module-fragment[opt] module-declaration +/// top-level-declaration-seq[opt] private-module-fragment[opt] +/// +/// Note that in C, it is an error if there is no first declaration. bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { Actions.ActOnStartOfTranslationUnit(); @@ -532,7 +549,7 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { // declaration. C++ doesn't have this restriction. We also don't want to // complain if we have a precompiled header, although technically if the PCH // is empty we should still emit the (pedantic) diagnostic. - bool NoTopLevelDecls = ParseTopLevelDecl(Result); + bool NoTopLevelDecls = ParseTopLevelDecl(Result, true); if (NoTopLevelDecls && !Actions.getASTContext().getExternalSource() && !getLangOpts().CPlusPlus) Diag(diag::ext_empty_translation_unit); @@ -542,7 +559,11 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the /// action tells us to. This returns true if the EOF was encountered. -bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { +/// +/// top-level-declaration: +/// declaration +/// [C++20] module-import-declaration +bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); // Skip over the EOF token, flagging end of previous input for incremental @@ -557,13 +578,46 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { return false; case tok::kw_export: - if (NextToken().isNot(tok::kw_module)) + switch (NextToken().getKind()) { + case tok::kw_module: + goto module_decl; + + // Note: no need to handle kw_import here. We only form kw_import under + // the Modules TS, and in that case 'export import' is parsed as an + // export-declaration containing an import-declaration. + + // Recognize context-sensitive C++20 'export module' and 'export import' + // declarations. + case tok::identifier: { + IdentifierInfo *II = NextToken().getIdentifierInfo(); + if ((II == Ident_module || II == Ident_import) && + GetLookAheadToken(2).isNot(tok::coloncolon)) { + if (II == Ident_module) + goto module_decl; + else + goto import_decl; + } break; - LLVM_FALLTHROUGH; + } + + default: + break; + } + break; + case tok::kw_module: - Result = ParseModuleDecl(); + module_decl: + Result = ParseModuleDecl(IsFirstDecl); return false; + // tok::kw_import is handled by ParseExternalDeclaration. (Under the Modules + // TS, an import can occur within an export block.) + import_decl: { + Decl *ImportDecl = ParseModuleImport(SourceLocation()); + Result = Actions.ConvertDeclToDeclGroup(ImportDecl); + return false; + } + case tok::annot_module_include: Actions.ActOnModuleInclude(Tok.getLocation(), reinterpret_cast<Module *>( @@ -595,6 +649,21 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { //else don't tell Sema that we ended parsing: more input might come. return true; + case tok::identifier: + // C++2a [basic.link]p3: + // A token sequence beginning with 'export[opt] module' or + // 'export[opt] import' and not immediately followed by '::' + // is never interpreted as the declaration of a top-level-declaration. + if ((Tok.getIdentifierInfo() == Ident_module || + Tok.getIdentifierInfo() == Ident_import) && + NextToken().isNot(tok::coloncolon)) { + if (Tok.getIdentifierInfo() == Ident_module) + goto module_decl; + else + goto import_decl; + } + break; + default: break; } @@ -2074,38 +2143,83 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { Braces.consumeClose(); } -/// Parse a C++ Modules TS module declaration, which appears at the beginning -/// of a module interface, module partition, or module implementation file. +/// Parse a declaration beginning with the 'module' keyword or C++20 +/// context-sensitive keyword (optionally preceded by 'export'). /// -/// module-declaration: [Modules TS + P0273R0 + P0629R0] -/// 'export'[opt] 'module' 'partition'[opt] -/// module-name attribute-specifier-seq[opt] ';' +/// module-declaration: [Modules TS + P0629R0] +/// 'export'[opt] 'module' module-name attribute-specifier-seq[opt] ';' /// -/// Note that 'partition' is a context-sensitive keyword. -Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { +/// global-module-fragment: [C++2a] +/// 'module' ';' top-level-declaration-seq[opt] +/// module-declaration: [C++2a] +/// 'export'[opt] 'module' module-name module-partition[opt] +/// attribute-specifier-seq[opt] ';' +/// private-module-fragment: [C++2a] +/// 'module' ':' 'private' ';' top-level-declaration-seq[opt] +Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) { SourceLocation StartLoc = Tok.getLocation(); Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export) ? Sema::ModuleDeclKind::Interface : Sema::ModuleDeclKind::Implementation; - assert(Tok.is(tok::kw_module) && "not a module declaration"); + assert( + (Tok.is(tok::kw_module) || + (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_module)) && + "not a module declaration"); SourceLocation ModuleLoc = ConsumeToken(); - if (Tok.is(tok::identifier) && NextToken().is(tok::identifier) && - Tok.getIdentifierInfo()->isStr("partition")) { - // If 'partition' is present, this must be a module interface unit. - if (MDK != Sema::ModuleDeclKind::Interface) - Diag(Tok.getLocation(), diag::err_module_implementation_partition) - << FixItHint::CreateInsertion(ModuleLoc, "export "); - MDK = Sema::ModuleDeclKind::Partition; + // Attributes appear after the module name, not before. + if (Tok.is(tok::l_square)) + CheckProhibitedCXX11Attribute(); + + // Parse a global-module-fragment, if present. + if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) { + SourceLocation SemiLoc = ConsumeToken(); + if (!IsFirstDecl) { + Diag(StartLoc, diag::err_global_module_introducer_not_at_start) + << SourceRange(StartLoc, SemiLoc); + return nullptr; + } + if (MDK == Sema::ModuleDeclKind::Interface) { + Diag(StartLoc, diag::err_module_fragment_exported) + << /*global*/0 << FixItHint::CreateRemoval(StartLoc); + } + return Actions.ActOnGlobalModuleFragmentDecl(ModuleLoc); + } + + // Parse a private-module-fragment, if present. + if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon) && + NextToken().is(tok::kw_private)) { + if (MDK == Sema::ModuleDeclKind::Interface) { + Diag(StartLoc, diag::err_module_fragment_exported) + << /*private*/1 << FixItHint::CreateRemoval(StartLoc); + } ConsumeToken(); + SourceLocation PrivateLoc = ConsumeToken(); + if (Tok.is(tok::l_square)) + CheckProhibitedCXX11Attribute(); + ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi); + return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc); } SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false)) return nullptr; + // Parse the optional module-partition. + if (Tok.is(tok::colon)) { + SourceLocation ColonLoc = ConsumeToken(); + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition; + if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/false)) + return nullptr; + + // FIXME: Support module partition declarations. + Diag(ColonLoc, diag::err_unsupported_module_partition) + << SourceRange(ColonLoc, Partition.back().second); + // Recover by parsing as a non-partition. + } + // We don't support any module attributes yet; just parse them and diagnose. ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); @@ -2113,7 +2227,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { ExpectAndConsumeSemi(diag::err_module_expected_semi); - return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path); + return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, IsFirstDecl); } /// Parse a module import declaration. This is essentially the same for @@ -2124,17 +2238,50 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { /// '@' 'import' module-name ';' /// [ModTS] module-import-declaration: /// 'import' module-name attribute-specifier-seq[opt] ';' +/// [C++2a] module-import-declaration: +/// 'export'[opt] 'import' module-name +/// attribute-specifier-seq[opt] ';' +/// 'export'[opt] 'import' module-partition +/// attribute-specifier-seq[opt] ';' +/// 'export'[opt] 'import' header-name +/// attribute-specifier-seq[opt] ';' Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { - assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import) + SourceLocation StartLoc = AtLoc.isInvalid() ? Tok.getLocation() : AtLoc; + + SourceLocation ExportLoc; + TryConsumeToken(tok::kw_export, ExportLoc); + + assert((AtLoc.isInvalid() ? Tok.isOneOf(tok::kw_import, tok::identifier) : Tok.isObjCAtKeyword(tok::objc_import)) && "Improper start to module import"); bool IsObjCAtImport = Tok.isObjCAtKeyword(tok::objc_import); SourceLocation ImportLoc = ConsumeToken(); - SourceLocation StartLoc = AtLoc.isInvalid() ? ImportLoc : AtLoc; SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; - if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + Module *HeaderUnit = nullptr; + + if (Tok.is(tok::header_name)) { + // This is a header import that the preprocessor decided we should skip + // because it was malformed in some way. Parse and ignore it; it's already + // been diagnosed. + ConsumeToken(); + } else if (Tok.is(tok::annot_header_unit)) { + // This is a header import that the preprocessor mapped to a module import. + HeaderUnit = reinterpret_cast<Module *>(Tok.getAnnotationValue()); + ConsumeAnnotationToken(); + } else if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon)) { + SourceLocation ColonLoc = ConsumeToken(); + if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + return nullptr; + + // FIXME: Support module partition import. + Diag(ColonLoc, diag::err_unsupported_module_partition) + << SourceRange(ColonLoc, Path.back().second); return nullptr; + } else { + if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + return nullptr; + } ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); @@ -2147,7 +2294,12 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { return nullptr; } - DeclResult Import = Actions.ActOnModuleImport(StartLoc, ImportLoc, Path); + DeclResult Import; + if (HeaderUnit) + Import = + Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, HeaderUnit); + else if (!Path.empty()) + Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path); ExpectAndConsumeSemi(diag::err_module_expected_semi); if (Import.isInvalid()) return nullptr; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index bc4fdfbe58e..befe6ac7630 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -849,24 +849,11 @@ void Sema::ActOnStartOfTranslationUnit() { if (getLangOpts().ModulesTS && (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface || getLangOpts().getCompilingModule() == LangOptions::CMK_None)) { + // We start in an implied global module fragment. 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). - 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); + ActOnGlobalModuleFragmentDecl(StartOfTU); + ModuleScopes.back().ImplicitGlobalModuleFragment = true; } } @@ -997,13 +984,24 @@ void Sema::ActOnEndOfTranslationUnit() { checkUndefinedButUsed(*this); } + // A global-module-fragment is only permitted within a module unit. + bool DiagnosedMissingModuleDeclaration = false; + if (!ModuleScopes.empty() && + ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment && + !ModuleScopes.back().ImplicitGlobalModuleFragment) { + Diag(ModuleScopes.back().BeginLoc, + diag::err_module_declaration_missing_after_global_module_introducer); + DiagnosedMissingModuleDeclaration = true; + } + if (TUKind == TU_Module) { // If we are building a module interface unit, we need to have seen the // module declaration by now. if (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface && (ModuleScopes.empty() || - ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)) { + ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) && + !DiagnosedMissingModuleDeclaration) { // FIXME: Make a better guess as to where to put the module declaration. Diag(getSourceManager().getLocForStartOfFile( getSourceManager().getMainFileID()), diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index fa29e8c904f..cb1a5b684a5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -17016,12 +17016,44 @@ static void checkModuleImportContext(Sema &S, Module *M, } } -Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, - SourceLocation ModuleLoc, - ModuleDeclKind MDK, - ModuleIdPath Path) { - assert(getLangOpts().ModulesTS && - "should only have module decl in modules TS"); +Sema::DeclGroupPtrTy +Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) { + if (!ModuleScopes.empty() && + ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) { + // Under -std=c++2a -fmodules-ts, we can find an explicit 'module;' after + // already implicitly entering the global module fragment. That's OK. + assert(getLangOpts().CPlusPlusModules && getLangOpts().ModulesTS && + "unexpectedly encountered multiple global module fragment decls"); + ModuleScopes.back().BeginLoc = ModuleLoc; + return nullptr; + } + + // 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); + assert(GlobalModule && "module creation should not fail"); + + // Enter the scope of the global module. + ModuleScopes.push_back({}); + ModuleScopes.back().BeginLoc = ModuleLoc; + ModuleScopes.back().Module = GlobalModule; + VisibleModules.setVisible(GlobalModule, ModuleLoc); + + // All declarations created from now on are owned by the global module. + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + TU->setLocalOwningModule(GlobalModule); + + // FIXME: Consider creating an explicit representation of this declaration. + return nullptr; +} + +Sema::DeclGroupPtrTy +Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, + ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl) { + assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) && + "should only have module decl in Modules TS or C++20"); // 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 @@ -17051,19 +17083,40 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, return nullptr; } - assert(ModuleScopes.size() == 1 && "expected to be at global module scope"); + assert(ModuleScopes.size() <= 1 && "expected to be at global module scope"); // FIXME: Most of this work should be done by the preprocessor rather than // here, in order to support macro import. // Only one module-declaration is permitted per source file. - if (ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) { + if (!ModuleScopes.empty() && + ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) { Diag(ModuleLoc, diag::err_module_redeclaration); Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module), diag::note_prev_module_declaration); return nullptr; } + // Find the global module fragment we're adopting into this module, if any. + Module *GlobalModuleFragment = nullptr; + if (!ModuleScopes.empty() && + ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) + GlobalModuleFragment = ModuleScopes.back().Module; + + // In C++20, the module-declaration must be the first declaration if there + // is no global module fragment. + if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !GlobalModuleFragment) { + Diag(ModuleLoc, diag::err_module_decl_not_at_start); + SourceLocation BeginLoc = + ModuleScopes.empty() + ? SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()) + : ModuleScopes.back().BeginLoc; + if (BeginLoc.isValid()) { + Diag(BeginLoc, diag::note_global_module_introducer_missing) + << FixItHint::CreateInsertion(BeginLoc, "module;\n"); + } + } + // Flatten the dots in a module name. Unlike Clang's hierarchical module map // modules, the dots here are just another character that can appear in a // module name. @@ -17105,15 +17158,11 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, // Create a Module for the module that we're defining. Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, - ModuleScopes.front().Module); + GlobalModuleFragment); assert(Mod && "module creation should not fail"); break; } - case ModuleDeclKind::Partition: - // FIXME: Check we are in a submodule of the named module. - return nullptr; - case ModuleDeclKind::Implementation: std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( PP.getIdentifierInfo(ModuleName), Path[0].second); @@ -17124,12 +17173,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName; // Create an empty module interface unit for error recovery. Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, - ModuleScopes.front().Module); + GlobalModuleFragment); } break; } - // Switch from the global module to the named module. + if (!GlobalModuleFragment) { + ModuleScopes.push_back({}); + if (getLangOpts().ModulesLocalVisibility) + ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); + } + + // Switch from the global module fragment (if any) to the named module. + ModuleScopes.back().BeginLoc = StartLoc; ModuleScopes.back().Module = Mod; ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation; VisibleModules.setVisible(Mod, ModuleLoc); @@ -17146,6 +17202,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, } DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, + SourceLocation ExportLoc, SourceLocation ImportLoc, ModuleIdPath Path) { // Flatten the module path for a Modules TS module name. @@ -17167,6 +17224,13 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, if (!Mod) return true; + return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path); +} + +DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, + SourceLocation ExportLoc, + SourceLocation ImportLoc, + Module *Mod, ModuleIdPath Path) { VisibleModules.setVisible(Mod, ImportLoc); checkModuleImportContext(*this, Mod, ImportLoc, CurContext); @@ -17176,12 +17240,15 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, // silently ignoring the import. // Import-from-implementation is valid in the Modules TS. FIXME: Should we // warn on a redundant import of the current module? + // FIXME: Import of a module from an implementation partition of the same + // module is permitted. if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && - (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) + (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) { Diag(ImportLoc, getLangOpts().isCompilingModule() ? diag::err_module_self_import : diag::err_module_import_in_implementation) << Mod->getFullModuleName() << getLangOpts().CurrentModule; + } SmallVector<SourceLocation, 2> IdentifierLocs; Module *ModCheck = Mod; @@ -17195,16 +17262,30 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, IdentifierLocs.push_back(Path[I].second); } + // If this was a header import, pad out with dummy locations. + // FIXME: Pass in and use the location of the header-name token in this case. + if (Path.empty()) { + for (; ModCheck; ModCheck = ModCheck->Parent) { + IdentifierLocs.push_back(SourceLocation()); + } + } + ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc, Mod, IdentifierLocs); + CurContext->addDecl(Import); + + // Sequence initialization of the imported module before that of the current + // module, if any. if (!ModuleScopes.empty()) Context.addModuleInitializer(ModuleScopes.back().Module, Import); - CurContext->addDecl(Import); // Re-export the module if needed. - if (Import->isExported() && - !ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) - getCurrentModule()->Exports.emplace_back(Mod, false); + if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) { + if (ExportLoc.isValid() || Import->isExported()) + getCurrentModule()->Exports.emplace_back(Mod, false); + } else if (ExportLoc.isValid()) { + Diag(ExportLoc, diag::err_export_not_in_module_interface); + } return Import; } |

