Changeset View
Changeset View
Standalone View
Standalone View
clang/lib/Sema/SemaModule.cpp
Show First 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) { | ||||
TU->setLocalOwningModule(GlobalModule); | TU->setLocalOwningModule(GlobalModule); | ||||
// FIXME: Consider creating an explicit representation of this declaration. | // FIXME: Consider creating an explicit representation of this declaration. | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
Sema::DeclGroupPtrTy | Sema::DeclGroupPtrTy | ||||
Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, | Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, | ||||
ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl) { | ModuleDeclKind MDK, ModuleIdPath Path, | ||||
ModuleIdPath PartitionPath, bool IsFirstDecl) { | |||||
assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) && | assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) && | ||||
"should only have module decl in Modules TS or C++20"); | "should only have module decl in Modules TS or C++20"); | ||||
// A module implementation unit requires that we are not compiling a module | // 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 | // of any kind. A module interface unit requires that we are not compiling a | ||||
// module map. | // module map. | ||||
switch (getLangOpts().getCompilingModule()) { | switch (getLangOpts().getCompilingModule()) { | ||||
case LangOptions::CMK_None: | case LangOptions::CMK_None: | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, | ||||
// module name. | // module name. | ||||
std::string ModuleName; | std::string ModuleName; | ||||
for (auto &Piece : Path) { | for (auto &Piece : Path) { | ||||
if (!ModuleName.empty()) | if (!ModuleName.empty()) | ||||
ModuleName += "."; | ModuleName += "."; | ||||
ModuleName += Piece.first->getName(); | ModuleName += Piece.first->getName(); | ||||
} | } | ||||
if (MDK == ModuleDeclKind::Partition) { | |||||
std::string PartitionName; | |||||
for (auto &Piece : PartitionPath) { | |||||
if (!PartitionName.empty()) | |||||
PartitionName += "."; | |||||
PartitionName += Piece.first->getName(); | |||||
} | |||||
ModuleName += "-" + PartitionName; | |||||
} | |||||
// If a module name was explicitly specified on the command line, it must be | // If a module name was explicitly specified on the command line, it must be | ||||
// correct. | // correct. | ||||
if (!getLangOpts().CurrentModule.empty() && | if (!getLangOpts().CurrentModule.empty() && | ||||
getLangOpts().CurrentModule != ModuleName) { | getLangOpts().CurrentModule != ModuleName) { | ||||
Diag(Path.front().second, diag::err_current_module_name_mismatch) | Diag(Path.front().second, diag::err_current_module_name_mismatch) | ||||
<< SourceRange(Path.front().second, Path.back().second) | << SourceRange(Path.front().second, Path.back().second) | ||||
<< getLangOpts().CurrentModule; | << getLangOpts().CurrentModule; | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; | const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; | ||||
auto &Map = PP.getHeaderSearchInfo().getModuleMap(); | auto &Map = PP.getHeaderSearchInfo().getModuleMap(); | ||||
Module *Mod; | Module *Mod; | ||||
switch (MDK) { | switch (MDK) { | ||||
case ModuleDeclKind::Partition: | |||||
case ModuleDeclKind::Interface: { | case ModuleDeclKind::Interface: { | ||||
// We can't have parsed or imported a definition of this module or parsed a | // We can't have parsed or imported a definition of this module or parsed a | ||||
// module map defining it already. | // module map defining it already. | ||||
if (auto *M = Map.findModule(ModuleName)) { | if (auto *M = Map.findModule(ModuleName)) { | ||||
Diag(Path[0].second, diag::err_module_redefinition) << ModuleName; | Diag(Path[0].second, diag::err_module_redefinition) << ModuleName; | ||||
if (M->DefinitionLoc.isValid()) | if (M->DefinitionLoc.isValid()) | ||||
Diag(M->DefinitionLoc, diag::note_prev_module_definition); | Diag(M->DefinitionLoc, diag::note_prev_module_definition); | ||||
else if (Optional<FileEntryRef> FE = M->getASTFile()) | else if (Optional<FileEntryRef> FE = M->getASTFile()) | ||||
Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) | Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) | ||||
<< FE->getName(); | << FE->getName(); | ||||
Mod = M; | Mod = M; | ||||
break; | break; | ||||
} | } | ||||
// Create a Module for the module that we're defining. | // Create a Module for the module that we're defining. | ||||
Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, | Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, | ||||
GlobalModuleFragment); | GlobalModuleFragment); | ||||
assert(Mod && "module creation should not fail"); | assert(Mod && "module creation should not fail"); | ||||
break; | break; | ||||
} | } | ||||
case ModuleDeclKind::Implementation: | case ModuleDeclKind::Implementation: | ||||
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( | std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( | ||||
PP.getIdentifierInfo(ModuleName), Path[0].second); | PP.getIdentifierInfo(ModuleName), Path[0].second); | ||||
Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, | Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, | ||||
if (!ModuleScopes.back().ModuleInterface) { | if (!ModuleScopes.back().ModuleInterface) { | ||||
Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface); | Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface); | ||||
Diag(ModuleScopes.back().BeginLoc, | Diag(ModuleScopes.back().BeginLoc, | ||||
diag::note_not_module_interface_add_export) | diag::note_not_module_interface_add_export) | ||||
<< FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); | << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
if (IsCurrentModulePartition()) { | |||||
Diag(PrivateLoc, diag::err_private_module_fragment_in_module_partition); | |||||
return nullptr; | |||||
} | |||||
// FIXME: Check this isn't a module interface partition. | // FIXME: Check this isn't a module interface partition. | ||||
// FIXME: Check that this translation unit does not import any partitions; | // 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" | // such imports would violate [basic.link]/2's "shall be the only module unit" | ||||
// restriction. | // restriction. | ||||
// We've finished the public fragment of the translation unit. | // We've finished the public fragment of the translation unit. | ||||
ActOnEndOfTranslationUnitFragment(TUFragmentKind::Normal); | ActOnEndOfTranslationUnitFragment(TUFragmentKind::Normal); | ||||
Show All 18 Lines | Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, | ||||
TU->setLocalOwningModule(PrivateModuleFragment); | TU->setLocalOwningModule(PrivateModuleFragment); | ||||
// FIXME: Consider creating an explicit representation of this declaration. | // FIXME: Consider creating an explicit representation of this declaration. | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, | DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, | ||||
SourceLocation ExportLoc, | SourceLocation ExportLoc, | ||||
SourceLocation ImportLoc, | SourceLocation ImportLoc, ModuleIdPath Path, | ||||
ModuleIdPath Path) { | bool IsPartition) { | ||||
// Flatten the module path for a Modules TS module name. | // Flatten the module path for a Modules TS module name. | ||||
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc; | std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc; | ||||
if (getLangOpts().ModulesTS) { | if (getLangOpts().ModulesTS || IsPartition) { | ||||
std::string ModuleName; | std::string ModuleName; | ||||
for (auto &Piece : Path) { | for (auto &Piece : Path) { | ||||
if (!ModuleName.empty()) | if (!ModuleName.empty()) | ||||
ModuleName += "."; | ModuleName += "."; | ||||
ModuleName += Piece.first->getName(); | ModuleName += Piece.first->getName(); | ||||
} | } | ||||
if (IsPartition) { | |||||
assert(getLangOpts().CPlusPlusModules && | |||||
"Partitions is only allowed in C++20 modules."); | |||||
if (getLangOpts().CurrentModule.empty()) | |||||
Diag(ImportLoc, diag::err_module_import_in_non_module); | |||||
ModuleName = std::string(getCurrentModuleName()) + "-" + ModuleName; | |||||
} | |||||
ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second}; | ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second}; | ||||
Path = ModuleIdPath(ModuleNameLoc); | Path = ModuleIdPath(ModuleNameLoc); | ||||
} | } | ||||
Module *Mod = | Module *Mod = | ||||
getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, | getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, | ||||
/*IsInclusionDirective=*/false); | /*IsInclusionDirective=*/false); | ||||
if (!Mod) | if (!Mod) | ||||
return true; | return true; | ||||
return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path); | return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path, | ||||
IsPartition); | |||||
} | } | ||||
/// Determine whether \p D is lexically within an export-declaration. | /// Determine whether \p D is lexically within an export-declaration. | ||||
static const ExportDecl *getEnclosingExportDecl(const Decl *D) { | static const ExportDecl *getEnclosingExportDecl(const Decl *D) { | ||||
for (auto *DC = D->getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) | for (auto *DC = D->getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) | ||||
if (auto *ED = dyn_cast<ExportDecl>(DC)) | if (auto *ED = dyn_cast<ExportDecl>(DC)) | ||||
return ED; | return ED; | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, | DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, | ||||
SourceLocation ExportLoc, | SourceLocation ExportLoc, | ||||
SourceLocation ImportLoc, | SourceLocation ImportLoc, Module *Mod, | ||||
Module *Mod, ModuleIdPath Path) { | ModuleIdPath Path, bool IsPartition) { | ||||
VisibleModules.setVisible(Mod, ImportLoc); | VisibleModules.setVisible(Mod, ImportLoc); | ||||
checkModuleImportContext(*this, Mod, ImportLoc, CurContext); | checkModuleImportContext(*this, Mod, ImportLoc, CurContext); | ||||
// FIXME: we should support importing a submodule within a different submodule | // FIXME: we should support importing a submodule within a different submodule | ||||
// of the same top-level module. Until we do, make it an error rather than | // of the same top-level module. Until we do, make it an error rather than | ||||
// silently ignoring the import. | // silently ignoring the import. | ||||
// Import-from-implementation is valid in the Modules TS. FIXME: Should we | // Import-from-implementation is valid in the Modules TS. FIXME: Should we | ||||
// warn on a redundant import of the current module? | // warn on a redundant import of the current module? | ||||
// FIXME: Import of a module from an implementation partition of the same | if (Mod->getTopLevelPrimaryModuleName() == getCurrentModuleName() && | ||||
// module is permitted. | (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS) && | ||||
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && | !IsPartition && !IsCurrentModulePartition()) { | ||||
(getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) { | |||||
Diag(ImportLoc, getLangOpts().isCompilingModule() | Diag(ImportLoc, getLangOpts().isCompilingModule() | ||||
? diag::err_module_self_import | ? diag::err_module_self_import | ||||
: diag::err_module_import_in_implementation) | : diag::err_module_import_in_implementation) | ||||
<< Mod->getFullModuleName() << getLangOpts().CurrentModule; | << Mod->getFullModuleName() << getCurrentModuleName(); | ||||
} | } | ||||
SmallVector<SourceLocation, 2> IdentifierLocs; | SmallVector<SourceLocation, 2> IdentifierLocs; | ||||
Module *ModCheck = Mod; | Module *ModCheck = Mod; | ||||
for (unsigned I = 0, N = Path.size(); I != N; ++I) { | for (unsigned I = 0, N = Path.size(); I != N; ++I) { | ||||
// If we've run out of module parents, just drop the remaining identifiers. | // If we've run out of module parents, just drop the remaining identifiers. | ||||
// We need the length to be consistent. | // We need the length to be consistent. | ||||
if (!ModCheck) | if (!ModCheck) | ||||
▲ Show 20 Lines • Show All 333 Lines • ▼ Show 20 Lines | for (auto *Child : ED->decls()) { | ||||
diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child, | diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child, | ||||
BlockStart); | BlockStart); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return D; | return D; | ||||
} | } | ||||
StringRef Sema::getCurrentModuleName() const { | |||||
if (!getLangOpts().CPlusPlusModules) | |||||
return getLangOpts().CurrentModule; | |||||
return StringRef(getLangOpts().CurrentModule).split('-').first; | |||||
} | |||||
bool Sema::IsCurrentModulePartition() const { | |||||
return StringRef(getLangOpts().CurrentModule).contains('-'); | |||||
} |