forked from OSchip/llvm-project
[modules] Frontend support for building a header module from a list of
headaer files. llvm-svn: 342304
This commit is contained in:
parent
66f3dc031d
commit
d6509cf21d
|
@ -187,6 +187,8 @@ def err_module_build_requires_fmodules : Error<
|
|||
"module compilation requires '-fmodules'">;
|
||||
def err_module_interface_requires_modules_ts : Error<
|
||||
"module interface compilation requires '-fmodules-ts'">;
|
||||
def err_header_module_requires_modules : Error<
|
||||
"header module compilation requires '-fmodules' or '-fmodules-ts'">;
|
||||
def warn_module_config_mismatch : Warning<
|
||||
"module file %0 cannot be loaded due to a configuration mismatch with the current "
|
||||
"compilation">, InGroup<DiagGroup<"module-file-config-mismatch">>, DefaultError;
|
||||
|
@ -224,6 +226,10 @@ def remark_module_build_done : Remark<"finished building module '%0'">,
|
|||
def err_modules_embed_file_not_found :
|
||||
Error<"file '%0' specified by '-fmodules-embed-file=' not found">,
|
||||
DefaultFatal;
|
||||
def err_module_header_file_not_found :
|
||||
Error<"module header file '%0' not found">, DefaultFatal;
|
||||
def err_module_header_file_invalid :
|
||||
Error<"unexpected module header file input '%0'">, DefaultFatal;
|
||||
|
||||
def err_test_module_file_extension_version : Error<
|
||||
"test module file extension '%0' has different version (%1.%2) than expected "
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace clang {
|
|||
enum {
|
||||
DIAG_SIZE_COMMON = 300,
|
||||
DIAG_SIZE_DRIVER = 200,
|
||||
DIAG_SIZE_FRONTEND = 100,
|
||||
DIAG_SIZE_FRONTEND = 150,
|
||||
DIAG_SIZE_SERIALIZATION = 120,
|
||||
DIAG_SIZE_LEX = 400,
|
||||
DIAG_SIZE_PARSE = 500,
|
||||
|
|
|
@ -9090,6 +9090,8 @@ def err_invalid_type_for_program_scope_var : Error<
|
|||
let CategoryName = "Modules Issue" in {
|
||||
def err_module_decl_in_module_map_module : Error<
|
||||
"'module' declaration found while building module from module map">;
|
||||
def err_module_decl_in_header_module : Error<
|
||||
"'module' declaration found while building header module">;
|
||||
def err_module_interface_implementation_mismatch : Error<
|
||||
"missing 'export' specifier in module declaration while "
|
||||
"building module interface">;
|
||||
|
|
|
@ -73,8 +73,11 @@ public:
|
|||
/// Compiling a module from a module map.
|
||||
CMK_ModuleMap,
|
||||
|
||||
/// Compiling a module from a list of header files.
|
||||
CMK_HeaderModule,
|
||||
|
||||
/// Compiling a C++ modules TS module interface unit.
|
||||
CMK_ModuleInterface
|
||||
CMK_ModuleInterface,
|
||||
};
|
||||
|
||||
enum PragmaMSPointersToMembersKind {
|
||||
|
|
|
@ -543,6 +543,8 @@ def emit_module : Flag<["-"], "emit-module">,
|
|||
HelpText<"Generate pre-compiled module file from a module map">;
|
||||
def emit_module_interface : Flag<["-"], "emit-module-interface">,
|
||||
HelpText<"Generate pre-compiled module file from a C++ module interface">;
|
||||
def emit_header_module : Flag<["-"], "emit-header-module">,
|
||||
HelpText<"Generate pre-compiled module file from a set of header files">;
|
||||
def emit_pth : Flag<["-"], "emit-pth">,
|
||||
HelpText<"Generate pre-tokenized header file">;
|
||||
def emit_pch : Flag<["-"], "emit-pch">,
|
||||
|
|
|
@ -48,6 +48,12 @@ protected:
|
|||
/// @name Implementation Action Interface
|
||||
/// @{
|
||||
|
||||
/// Prepare to execute the action on the given CompilerInstance.
|
||||
///
|
||||
/// This is called before executing the action on any inputs, and can modify
|
||||
/// the configuration as needed (including adjusting the input list).
|
||||
virtual bool PrepareToExecuteAction(CompilerInstance &CI) { return true; }
|
||||
|
||||
/// Create the AST consumer object for this action, if supported.
|
||||
///
|
||||
/// This routine is called as part of BeginSourceFile(), which will
|
||||
|
@ -130,11 +136,18 @@ public:
|
|||
return CurrentInput;
|
||||
}
|
||||
|
||||
const StringRef getCurrentFile() const {
|
||||
StringRef getCurrentFile() const {
|
||||
assert(!CurrentInput.isEmpty() && "No current file!");
|
||||
return CurrentInput.getFile();
|
||||
}
|
||||
|
||||
StringRef getCurrentFileOrBufferName() const {
|
||||
assert(!CurrentInput.isEmpty() && "No current file!");
|
||||
return CurrentInput.isFile()
|
||||
? CurrentInput.getFile()
|
||||
: CurrentInput.getBuffer()->getBufferIdentifier();
|
||||
}
|
||||
|
||||
InputKind getCurrentFileKind() const {
|
||||
assert(!CurrentInput.isEmpty() && "No current file!");
|
||||
return CurrentInput.getKind();
|
||||
|
@ -190,6 +203,11 @@ public:
|
|||
/// @name Public Action Interface
|
||||
/// @{
|
||||
|
||||
/// Prepare the action to execute on the given compiler instance.
|
||||
bool PrepareToExecute(CompilerInstance &CI) {
|
||||
return PrepareToExecuteAction(CI);
|
||||
}
|
||||
|
||||
/// Prepare the action for processing the input file \p Input.
|
||||
///
|
||||
/// This is run after the options and frontend have been initialized,
|
||||
|
|
|
@ -142,6 +142,19 @@ private:
|
|||
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
|
||||
};
|
||||
|
||||
class GenerateHeaderModuleAction : public GenerateModuleAction {
|
||||
/// The synthesized module input buffer for the current compilation.
|
||||
std::unique_ptr<llvm::MemoryBuffer> Buffer;
|
||||
std::vector<std::string> ModuleHeaders;
|
||||
|
||||
private:
|
||||
bool PrepareToExecuteAction(CompilerInstance &CI) override;
|
||||
bool BeginSourceFileAction(CompilerInstance &CI) override;
|
||||
|
||||
std::unique_ptr<raw_pwrite_stream>
|
||||
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
|
||||
};
|
||||
|
||||
class SyntaxOnlyAction : public ASTFrontendAction {
|
||||
protected:
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
||||
|
|
|
@ -82,6 +82,9 @@ enum ActionKind {
|
|||
/// Generate pre-compiled module from a C++ module interface file.
|
||||
GenerateModuleInterface,
|
||||
|
||||
/// Generate pre-compiled module from a set of header files.
|
||||
GenerateHeaderModule,
|
||||
|
||||
/// Generate pre-compiled header.
|
||||
GeneratePCH,
|
||||
|
||||
|
|
|
@ -92,9 +92,9 @@ class ModuleMap {
|
|||
/// named LangOpts::CurrentModule, if we've loaded it).
|
||||
Module *SourceModule = nullptr;
|
||||
|
||||
/// The global module for the current TU, if we still own it. (Ownership is
|
||||
/// transferred if/when we create an enclosing module.
|
||||
std::unique_ptr<Module> PendingGlobalModule;
|
||||
/// Submodules of the current module that have not yet been attached to it.
|
||||
/// (Ownership is transferred if/when we create an enclosing module.)
|
||||
llvm::SmallVector<std::unique_ptr<Module>, 8> PendingSubmodules;
|
||||
|
||||
/// The top-level modules that are known.
|
||||
llvm::StringMap<Module *> Modules;
|
||||
|
@ -519,8 +519,7 @@ public:
|
|||
bool IsFramework,
|
||||
bool IsExplicit);
|
||||
|
||||
/// Create a 'global module' for a C++ Modules TS module interface
|
||||
/// unit.
|
||||
/// 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
|
||||
|
@ -537,6 +536,9 @@ public:
|
|||
Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name,
|
||||
Module *GlobalModule);
|
||||
|
||||
/// Create a header module from the specified list of headers.
|
||||
Module *createHeaderModule(StringRef Name, ArrayRef<Module::Header> Headers);
|
||||
|
||||
/// Infer the contents of a framework module map from the given
|
||||
/// framework directory.
|
||||
Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir,
|
||||
|
|
|
@ -911,6 +911,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
|
|||
// taking it as an input instead of hard-coding llvm::errs.
|
||||
raw_ostream &OS = llvm::errs();
|
||||
|
||||
if (!Act.PrepareToExecute(*this))
|
||||
return false;
|
||||
|
||||
// Create the target instance.
|
||||
setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(),
|
||||
getInvocation().TargetOpts));
|
||||
|
@ -1615,22 +1618,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
|||
Module::NameVisibilityKind Visibility,
|
||||
bool IsInclusionDirective) {
|
||||
// Determine what file we're searching from.
|
||||
// FIXME: Should we be deciding whether this is a submodule (here and
|
||||
// below) based on -fmodules-ts or should we pass a flag and make the
|
||||
// caller decide?
|
||||
std::string ModuleName;
|
||||
if (getLangOpts().ModulesTS) {
|
||||
// FIXME: Same code as Sema::ActOnModuleDecl() so there is probably a
|
||||
// better place/way to do this.
|
||||
for (auto &Piece : Path) {
|
||||
if (!ModuleName.empty())
|
||||
ModuleName += ".";
|
||||
ModuleName += Piece.first->getName();
|
||||
}
|
||||
}
|
||||
else
|
||||
ModuleName = Path[0].first->getName();
|
||||
|
||||
StringRef ModuleName = Path[0].first->getName();
|
||||
SourceLocation ModuleNameLoc = Path[0].second;
|
||||
|
||||
// If we've already handled this import, just return the cached result.
|
||||
|
@ -1859,7 +1847,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
|||
// Verify that the rest of the module path actually corresponds to
|
||||
// a submodule.
|
||||
bool MapPrivateSubModToTopLevel = false;
|
||||
if (!getLangOpts().ModulesTS && Path.size() > 1) {
|
||||
if (Path.size() > 1) {
|
||||
for (unsigned I = 1, N = Path.size(); I != N; ++I) {
|
||||
StringRef Name = Path[I].first->getName();
|
||||
clang::Module *Sub = Module->findSubmodule(Name);
|
||||
|
|
|
@ -1454,6 +1454,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
|||
Opts.ProgramAction = frontend::GenerateModule; break;
|
||||
case OPT_emit_module_interface:
|
||||
Opts.ProgramAction = frontend::GenerateModuleInterface; break;
|
||||
case OPT_emit_header_module:
|
||||
Opts.ProgramAction = frontend::GenerateHeaderModule; break;
|
||||
case OPT_emit_pch:
|
||||
Opts.ProgramAction = frontend::GeneratePCH; break;
|
||||
case OPT_emit_pth:
|
||||
|
@ -2830,6 +2832,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
|
|||
case frontend::FixIt:
|
||||
case frontend::GenerateModule:
|
||||
case frontend::GenerateModuleInterface:
|
||||
case frontend::GenerateHeaderModule:
|
||||
case frontend::GeneratePCH:
|
||||
case frontend::GeneratePTH:
|
||||
case frontend::ParseSyntaxOnly:
|
||||
|
|
|
@ -523,7 +523,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
|
|||
setCurrentInput(Input);
|
||||
setCompilerInstance(&CI);
|
||||
|
||||
StringRef InputFile = Input.getFile();
|
||||
bool HasBegunSourceFile = false;
|
||||
bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled &&
|
||||
usesPreprocessorOnly();
|
||||
|
@ -541,6 +540,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
|
|||
&Diags->getDiagnosticOptions()));
|
||||
ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
|
||||
|
||||
// FIXME: What if the input is a memory buffer?
|
||||
StringRef InputFile = Input.getFile();
|
||||
|
||||
std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
|
||||
InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
|
||||
ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
|
||||
|
@ -604,6 +606,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
|
|||
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
|
||||
|
||||
// FIXME: What if the input is a memory buffer?
|
||||
StringRef InputFile = Input.getFile();
|
||||
|
||||
std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
|
||||
InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
|
||||
CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
|
||||
|
@ -791,7 +796,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
|
|||
|
||||
// For preprocessed files, check if the first line specifies the original
|
||||
// source file name with a linemarker.
|
||||
std::string PresumedInputFile = InputFile;
|
||||
std::string PresumedInputFile = getCurrentFileOrBufferName();
|
||||
if (Input.isPreprocessed())
|
||||
ReadOriginalFileName(CI, PresumedInputFile);
|
||||
|
||||
|
|
|
@ -242,6 +242,76 @@ GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,
|
|||
return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
|
||||
}
|
||||
|
||||
bool GenerateHeaderModuleAction::PrepareToExecuteAction(
|
||||
CompilerInstance &CI) {
|
||||
if (!CI.getLangOpts().Modules && !CI.getLangOpts().ModulesTS) {
|
||||
CI.getDiagnostics().Report(diag::err_header_module_requires_modules);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &Inputs = CI.getFrontendOpts().Inputs;
|
||||
if (Inputs.empty())
|
||||
return GenerateModuleAction::BeginInvocation(CI);
|
||||
|
||||
auto Kind = Inputs[0].getKind();
|
||||
|
||||
// Convert the header file inputs into a single module input buffer.
|
||||
SmallString<256> HeaderContents;
|
||||
ModuleHeaders.reserve(Inputs.size());
|
||||
for (const FrontendInputFile &FIF : Inputs) {
|
||||
// FIXME: We should support re-compiling from an AST file.
|
||||
if (FIF.getKind().getFormat() != InputKind::Source || !FIF.isFile()) {
|
||||
CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
|
||||
<< (FIF.isFile() ? FIF.getFile()
|
||||
: FIF.getBuffer()->getBufferIdentifier());
|
||||
return true;
|
||||
}
|
||||
|
||||
HeaderContents += "#include \"";
|
||||
HeaderContents += FIF.getFile();
|
||||
HeaderContents += "\"\n";
|
||||
ModuleHeaders.push_back(FIF.getFile());
|
||||
}
|
||||
Buffer = llvm::MemoryBuffer::getMemBufferCopy(
|
||||
HeaderContents, Module::getModuleInputBufferName());
|
||||
|
||||
// Set that buffer up as our "real" input.
|
||||
Inputs.clear();
|
||||
Inputs.push_back(FrontendInputFile(Buffer.get(), Kind, /*IsSystem*/false));
|
||||
|
||||
return GenerateModuleAction::PrepareToExecuteAction(CI);
|
||||
}
|
||||
|
||||
bool GenerateHeaderModuleAction::BeginSourceFileAction(
|
||||
CompilerInstance &CI) {
|
||||
CI.getLangOpts().setCompilingModule(LangOptions::CMK_HeaderModule);
|
||||
|
||||
// Synthesize a Module object for the given headers.
|
||||
auto &HS = CI.getPreprocessor().getHeaderSearchInfo();
|
||||
SmallVector<Module::Header, 16> Headers;
|
||||
for (StringRef Name : ModuleHeaders) {
|
||||
const DirectoryLookup *CurDir = nullptr;
|
||||
const FileEntry *FE = HS.LookupFile(
|
||||
Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir,
|
||||
None, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
if (!FE) {
|
||||
CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
|
||||
<< Name;
|
||||
continue;
|
||||
}
|
||||
Headers.push_back({Name, FE});
|
||||
}
|
||||
HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers);
|
||||
|
||||
return GenerateModuleAction::BeginSourceFileAction(CI);
|
||||
}
|
||||
|
||||
std::unique_ptr<raw_pwrite_stream>
|
||||
GenerateHeaderModuleAction::CreateOutputFile(CompilerInstance &CI,
|
||||
StringRef InFile) {
|
||||
return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
|
||||
}
|
||||
|
||||
SyntaxOnlyAction::~SyntaxOnlyAction() {
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
|
|||
return llvm::make_unique<GenerateModuleFromModuleMapAction>();
|
||||
case GenerateModuleInterface:
|
||||
return llvm::make_unique<GenerateModuleInterfaceAction>();
|
||||
case GenerateHeaderModule:
|
||||
return llvm::make_unique<GenerateHeaderModuleAction>();
|
||||
case GeneratePCH: return llvm::make_unique<GeneratePCHAction>();
|
||||
case GeneratePTH: return llvm::make_unique<GeneratePTHAction>();
|
||||
case InitOnly: return llvm::make_unique<InitOnlyAction>();
|
||||
|
|
|
@ -806,12 +806,11 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
|
|||
}
|
||||
|
||||
Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) {
|
||||
assert(!PendingGlobalModule && "created multiple global modules");
|
||||
PendingGlobalModule.reset(
|
||||
PendingSubmodules.emplace_back(
|
||||
new Module("<global>", Loc, nullptr, /*IsFramework*/ false,
|
||||
/*IsExplicit*/ true, NumCreatedModules++));
|
||||
PendingGlobalModule->Kind = Module::GlobalModuleFragment;
|
||||
return PendingGlobalModule.get();
|
||||
PendingSubmodules.back()->Kind = Module::GlobalModuleFragment;
|
||||
return PendingSubmodules.back().get();
|
||||
}
|
||||
|
||||
Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
|
||||
|
@ -827,10 +826,11 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
|
|||
Modules[Name] = SourceModule = Result;
|
||||
|
||||
// Reparent the current global module fragment as a submodule of this module.
|
||||
assert(GlobalModule == PendingGlobalModule.get() &&
|
||||
"unexpected global module");
|
||||
GlobalModule->setParent(Result);
|
||||
PendingGlobalModule.release(); // now owned by parent
|
||||
for (auto &Submodule : PendingSubmodules) {
|
||||
Submodule->setParent(Result);
|
||||
Submodule.release(); // now owned by parent
|
||||
}
|
||||
PendingSubmodules.clear();
|
||||
|
||||
// Mark the main source file as being within the newly-created module so that
|
||||
// declarations and macros are properly visibility-restricted to it.
|
||||
|
@ -841,6 +841,29 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
|
|||
return Result;
|
||||
}
|
||||
|
||||
Module *ModuleMap::createHeaderModule(StringRef Name,
|
||||
ArrayRef<Module::Header> Headers) {
|
||||
assert(LangOpts.CurrentModule == Name && "module name mismatch");
|
||||
assert(!Modules[Name] && "redefining existing module");
|
||||
|
||||
auto *Result =
|
||||
new Module(Name, SourceLocation(), nullptr, /*IsFramework*/ false,
|
||||
/*IsExplicit*/ false, NumCreatedModules++);
|
||||
Result->Kind = Module::ModuleInterfaceUnit;
|
||||
Modules[Name] = SourceModule = Result;
|
||||
|
||||
for (const Module::Header &H : Headers) {
|
||||
auto *M = new Module(H.NameAsWritten, SourceLocation(), Result,
|
||||
/*IsFramework*/ false,
|
||||
/*IsExplicit*/ true, NumCreatedModules++);
|
||||
// Header modules are implicitly 'export *'.
|
||||
M->Exports.push_back(Module::ExportDecl(nullptr, true));
|
||||
addHeader(M, H, NormalHeader);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// For a framework module, infer the framework against which we
|
||||
/// should link.
|
||||
static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir,
|
||||
|
|
|
@ -977,7 +977,8 @@ void Sema::ActOnEndOfTranslationUnit() {
|
|||
// module declaration by now.
|
||||
if (getLangOpts().getCompilingModule() ==
|
||||
LangOptions::CMK_ModuleInterface &&
|
||||
ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) {
|
||||
(ModuleScopes.empty() ||
|
||||
ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)) {
|
||||
// FIXME: Make a better guess as to where to put the module declaration.
|
||||
Diag(getSourceManager().getLocForStartOfFile(
|
||||
getSourceManager().getMainFileID()),
|
||||
|
|
|
@ -16832,6 +16832,10 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
|
|||
case LangOptions::CMK_ModuleMap:
|
||||
Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
|
||||
return nullptr;
|
||||
|
||||
case LangOptions::CMK_HeaderModule:
|
||||
Diag(ModuleLoc, diag::err_module_decl_in_header_module);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(ModuleScopes.size() == 1 && "expected to be at global module scope");
|
||||
|
@ -16900,7 +16904,8 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
|
|||
case ModuleDeclKind::Implementation:
|
||||
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
|
||||
PP.getIdentifierInfo(ModuleName), Path[0].second);
|
||||
Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible,
|
||||
Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
|
||||
Module::AllVisible,
|
||||
/*IsIncludeDirective=*/false);
|
||||
if (!Mod) {
|
||||
Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
|
||||
|
@ -16930,6 +16935,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
|
|||
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
|
||||
SourceLocation ImportLoc,
|
||||
ModuleIdPath Path) {
|
||||
// Flatten the module path for a Modules TS module name.
|
||||
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
|
||||
if (getLangOpts().ModulesTS) {
|
||||
std::string ModuleName;
|
||||
for (auto &Piece : Path) {
|
||||
if (!ModuleName.empty())
|
||||
ModuleName += ".";
|
||||
ModuleName += Piece.first->getName();
|
||||
}
|
||||
ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second};
|
||||
Path = ModuleIdPath(ModuleNameLoc);
|
||||
}
|
||||
|
||||
Module *Mod =
|
||||
getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible,
|
||||
/*IsIncludeDirective=*/false);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef A_H
|
||||
#define A_H
|
||||
void a();
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
#ifndef B_H
|
||||
#define B_H
|
||||
#include "a.h"
|
||||
void b();
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
// RUN: %clang_cc1 -fmodules-ts -fmodule-name=ab -x c++-header %S/Inputs/no-module-map/a.h %S/Inputs/no-module-map/b.h -emit-header-module -o %t.pcm
|
||||
// RUN: %clang_cc1 -fmodules-ts -fmodule-file=%t.pcm %s -I%S/Inputs/no-module-map -verify
|
||||
// RUN: %clang_cc1 -fmodules-ts -fmodule-file=%t.pcm %s -I%S/Inputs/no-module-map -verify -DA
|
||||
// RUN: %clang_cc1 -fmodules-ts -fmodule-file=%t.pcm %s -I%S/Inputs/no-module-map -verify -DB
|
||||
// RUN: %clang_cc1 -fmodules-ts -fmodule-file=%t.pcm %s -I%S/Inputs/no-module-map -verify -DA -DB
|
||||
|
||||
#ifdef B
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
#ifdef A
|
||||
#include "a.h"
|
||||
#endif
|
||||
|
||||
#ifdef B
|
||||
#include "b.h"
|
||||
#endif
|
||||
|
||||
#if defined(A) || defined(B)
|
||||
#ifndef A_H
|
||||
#error A_H should be defined
|
||||
#endif
|
||||
#else
|
||||
#ifdef A_H
|
||||
#error A_H should not be defined
|
||||
#endif
|
||||
// expected-error@+3 {{must be imported from}}
|
||||
// expected-note@* {{previous declaration}}
|
||||
#endif
|
||||
void use_a() { a(); }
|
||||
|
||||
#if defined(B)
|
||||
#ifndef B_H
|
||||
#error B_H should be defined
|
||||
#endif
|
||||
#else
|
||||
#ifdef B_H
|
||||
#error B_H should not be defined
|
||||
#endif
|
||||
// expected-error@+3 {{must be imported from}}
|
||||
// expected-note@* {{previous declaration}}
|
||||
#endif
|
||||
void use_b() { b(); }
|
Loading…
Reference in New Issue