InGroup<DiagGroup<"analyzer-incompatible-plugin"> >;
def note_incompatible_analyzer_plugin_api : Note<
"current API version is '%0', but plugin was compiled with version '%1'">;
-
+
def err_module_map_not_found : Error<"module map file '%0' not found">,
DefaultFatal;
def err_missing_module_name : Error<
def err_conflicting_module_names : Error<
"conflicting module names specified: '-fmodule-name=%0' and "
"'-fmodule-implementation-of %1'">;
+def err_module_already_loaded : Error<
+ "module '%0' has already been loaded; cannot load module file '%1'">;
+def err_module_file_not_module : Error<
+ "AST file '%0' was not built as a module">, DefaultFatal;
def err_missing_vfs_overlay_file : Error<
"virtual filesystem overlay file '%0' not found">, DefaultFatal;
"PCH file contains compiler errors">;
def err_imported_module_not_found : Error<
- "module '%0' imported by AST file '%1' not found">, DefaultFatal;
+ "module '%0' in AST file '%1' (imported by AST file '%2') "
+ "is not defined in any loaded module map file; "
+ "maybe you need to load '%3'?">, DefaultFatal;
def err_imported_module_modmap_changed : Error<
"module '%0' imported by AST file '%1' found in a different module map file"
" (%2) than when the importing AST file was built (%3)">, DefaultFatal;
def fmodules_validate_once_per_build_session : Flag<["-"], "fmodules-validate-once-per-build-session">,
Group<i_Group>, Flags<[CC1Option]>,
HelpText<"Don't verify input files for the modules if the module has been "
- "successfully validate or loaded during this build session">;
+ "successfully validated or loaded during this build session">;
def fmodules_validate_system_headers : Flag<["-"], "fmodules-validate-system-headers">,
Group<i_Group>, Flags<[CC1Option]>,
HelpText<"Validate the system headers that a module depends on when loading the module">;
def fmodule_map_file : Joined<["-"], "fmodule-map-file=">,
Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<file>">,
HelpText<"Load this module map file">;
+def fmodule_file : Joined<["-"], "fmodule-file=">,
+ Group<f_Group>, Flags<[DriverOption,CC1Option]>,
+ HelpText<"Load this precompiled module file">, MetaVarName<"<file>">;
def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Ignore the definition of the given macro when building and loading modules">;
def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>,
// Create module manager.
void createModuleManager();
+ ModuleLoadResult loadModuleFile(StringRef FileName, SourceLocation Loc);
+
ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) override;
/// The list of plugins to load.
std::vector<std::string> Plugins;
+ /// \brief The list of additional prebuilt module files to load before
+ /// processing the input.
+ std::vector<std::string> ModuleFiles;
+
/// \brief The list of AST files to merge.
std::vector<std::string> ASTMergeFiles;
std::unique_ptr<ASTReaderListener> Second)
: First(std::move(First)), Second(std::move(Second)) {}
+ std::unique_ptr<ASTReaderListener> takeFirst() { return std::move(First); }
+ std::unique_ptr<ASTReaderListener> takeSecond() { return std::move(Second); }
+
bool ReadFullVersionInformation(StringRef FullVersion) override;
void ReadModuleName(StringRef ModuleName) override;
void ReadModuleMapFile(StringRef ModuleMapPath) override;
void makeNamesVisible(const HiddenNames &Names, Module *Owner,
bool FromFinalization);
+ /// \brief Take the AST callbacks listener.
+ std::unique_ptr<ASTReaderListener> takeListener() {
+ return std::move(Listener);
+ }
+
/// \brief Set the AST callbacks listener.
void setListener(std::unique_ptr<ASTReaderListener> Listener) {
this->Listener = std::move(Listener);
}
- /// \brief Add an AST callbak listener.
+ /// \brief Add an AST callback listener.
///
/// Takes ownership of \p L.
void addListener(std::unique_ptr<ASTReaderListener> L) {
Listener = std::move(L);
}
+ /// RAII object to temporarily add an AST callback listener.
+ class ListenerScope {
+ ASTReader &Reader;
+ bool Chained;
+
+ public:
+ ListenerScope(ASTReader &Reader, std::unique_ptr<ASTReaderListener> L)
+ : Reader(Reader), Chained(false) {
+ auto Old = Reader.takeListener();
+ if (Old) {
+ Chained = true;
+ L = llvm::make_unique<ChainedASTReaderListener>(std::move(L),
+ std::move(Old));
+ }
+ Reader.setListener(std::move(L));
+ }
+ ~ListenerScope() {
+ auto New = Reader.takeListener();
+ if (Chained)
+ Reader.setListener(static_cast<ChainedASTReaderListener *>(New.get())
+ ->takeSecond());
+ }
+ };
+
/// \brief Set the AST deserialization listener.
void setDeserializationListener(ASTDeserializationListener *Listener,
bool TakeOwnership = false);
/// \brief Specifies the kind of module that has been loaded.
enum ModuleKind {
- MK_Module, ///< File is a module proper.
- MK_PCH, ///< File is a PCH file treated as such.
- MK_Preamble, ///< File is a PCH file treated as the preamble.
- MK_MainFile ///< File is a PCH file treated as the actual main file.
+ MK_ImplicitModule, ///< File is an implicitly-loaded module.
+ MK_ExplicitModule, ///< File is an explicitly-loaded module.
+ MK_PCH, ///< File is a PCH file treated as such.
+ MK_Preamble, ///< File is a PCH file treated as the preamble.
+ MK_MainFile ///< File is a PCH file treated as the actual main file.
};
/// \brief Information about the contents of a DeclContext.
// definitions.
Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file);
- // -fmodule-cache-path specifies where our module files should be written.
+ // -fmodule-file can be used to specify files containing precompiled modules.
+ Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file);
+
+ // -fmodule-cache-path specifies where our implicitly-built module files
+ // should be written.
SmallString<128> ModuleCachePath;
if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path))
ModuleCachePath = A->getValue();
static bool PCHLocator(serialization::ModuleFile &M, void *UserData) {
PCHLocatorInfo &Info = *static_cast<PCHLocatorInfo*>(UserData);
switch (M.Kind) {
- case serialization::MK_Module:
+ case serialization::MK_ImplicitModule:
+ case serialization::MK_ExplicitModule:
return true; // skip dependencies.
case serialization::MK_PCH:
Info.Mod = &M;
// Try to read the module file, now that we've compiled it.
ASTReader::ASTReadResult ReadResult =
ImportingInstance.getModuleManager()->ReadAST(
- ModuleFileName, serialization::MK_Module, ImportLoc,
+ ModuleFileName, serialization::MK_ImplicitModule, ImportLoc,
ModuleLoadCapabilities);
if (ReadResult == ASTReader::OutOfDate &&
}
ModuleLoadResult
+CompilerInstance::loadModuleFile(StringRef FileName, SourceLocation Loc) {
+ if (!ModuleManager)
+ createModuleManager();
+ if (!ModuleManager)
+ return ModuleLoadResult();
+
+ // Load the module if this is the first time we've been told about this file.
+ auto *MF = ModuleManager->getModuleManager().lookup(FileName);
+ if (!MF) {
+ struct ReadModuleNameListener : ASTReaderListener {
+ std::function<void(StringRef)> OnRead;
+ ReadModuleNameListener(std::function<void(StringRef)> F) : OnRead(F) {}
+ void ReadModuleName(StringRef ModuleName) override { OnRead(ModuleName); }
+ };
+
+ // Register listener to track the modules that are loaded by explicitly
+ // loading a module file. We suppress any attempts to implicitly load
+ // module files for any such module.
+ ASTReader::ListenerScope OnReadModuleName(
+ *ModuleManager,
+ llvm::make_unique<ReadModuleNameListener>([&](StringRef ModuleName) {
+ auto &PP = getPreprocessor();
+ auto *NameII = PP.getIdentifierInfo(ModuleName);
+ auto *Module = PP.getHeaderSearchInfo().lookupModule(ModuleName, false);
+ if (!KnownModules.insert(std::make_pair(NameII, Module)).second)
+ getDiagnostics().Report(Loc, diag::err_module_already_loaded)
+ << ModuleName << FileName;
+ }));
+
+ if (ModuleManager->ReadAST(FileName, serialization::MK_ExplicitModule, Loc,
+ ASTReader::ARR_None) != ASTReader::Success)
+ return ModuleLoadResult();
+
+ MF = ModuleManager->getModuleManager().lookup(FileName);
+ assert(MF && "unexpectedly failed to load module file");
+ }
+
+ if (MF->ModuleName.empty()) {
+ getDiagnostics().Report(Loc, diag::err_module_file_not_module)
+ << FileName;
+ return ModuleLoadResult();
+ }
+ auto *Module = PP->getHeaderSearchInfo().lookupModule(MF->ModuleName, false);
+ return ModuleLoadResult(Module, false);
+}
+
+ModuleLoadResult
CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
// Try to load the module file.
unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
- switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module,
- ImportLoc, ARRFlags)) {
+ switch (ModuleManager->ReadAST(ModuleFileName,
+ serialization::MK_ImplicitModule, ImportLoc,
+ ARRFlags)) {
case ASTReader::Success:
break;
Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups);
Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex;
-
+ Opts.ModuleFiles = Args.getAllArgValues(OPT_fmodule_file);
+
Opts.CodeCompleteOpts.IncludeMacros
= Args.hasArg(OPT_code_completion_macros);
Opts.CodeCompleteOpts.IncludeCodePatterns
// FIXME: should not overwrite ASTMutationListener when parsing model files?
if (!isModelParsingAction())
CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
-
+
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
IntrusiveRefCntPtr<ExternalSemaSource> source, FinalReader;
"doesn't support modules");
}
+ // If we were asked to load any module files, do so now. Don't make any names
+ // from those modules visible.
+ for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles) {
+ // FIXME: Use a better source location here. Perhaps inject something
+ // into the predefines buffer to represent these module files.
+ if (!CI.loadModuleFile(ModuleFile,
+ CI.getSourceManager().getLocForStartOfFile(
+ CI.getSourceManager().getMainFileID())))
+ goto failure;
+ }
+
// If there is a layout overrides file, attach an external AST source that
// provides the layouts from that file.
if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
// If the original import came from a file explicitly generated by the user,
// don't check the diagnostic mappings.
// FIXME: currently this is approximated by checking whether this is not a
- // module import.
+ // module import of an implicitly-loaded module file.
// Note: ModuleMgr.rbegin() may not be the current module, but it must be in
// the transitive closure of its imports, since unrelated modules cannot be
// imported until after this module finishes validation.
ModuleFile *TopImport = *ModuleMgr.rbegin();
while (!TopImport->ImportedBy.empty())
TopImport = TopImport->ImportedBy[0];
- if (TopImport->Kind != MK_Module)
+ if (TopImport->Kind != MK_ImplicitModule)
return false;
StringRef ModuleName = TopImport->ModuleName;
}
}
- if (F.Kind == MK_Module) {
+ if (F.Kind == MK_ImplicitModule || F.Kind == MK_ExplicitModule) {
// Macro definitions are stored from newest to oldest, so reverse them
// before registering them.
llvm::SmallVector<unsigned, 8> MacroSizes;
SrcMgr::CharacteristicKind
FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
- if (IncludeLoc.isInvalid() && F->Kind == MK_Module) {
+ if (IncludeLoc.isInvalid() &&
+ (F->Kind == MK_ImplicitModule || F->Kind == MK_ExplicitModule)) {
IncludeLoc = getImportLocation(F);
}
unsigned Code = SLocEntryCursor.ReadCode();
// Find which module file this entry lands in.
ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
- if (M->Kind != MK_Module)
+ if (M->Kind != MK_ImplicitModule && M->Kind != MK_ExplicitModule)
return std::make_pair(SourceLocation(), "");
// FIXME: Can we map this down to a particular submodule? That would be
const PendingMacroInfo &PMInfo) {
assert(II);
- if (PMInfo.M->Kind != MK_Module) {
+ if (PMInfo.M->Kind != MK_ImplicitModule &&
+ PMInfo.M->Kind != MK_ExplicitModule) {
installPCHMacroDirectives(II, *PMInfo.M,
PMInfo.PCHMacroData.MacroDirectivesOffset);
return;
void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
ModuleFile &M, uint64_t Offset) {
- assert(M.Kind != MK_Module);
+ assert(M.Kind != MK_ImplicitModule && M.Kind != MK_ExplicitModule);
BitstreamCursor &Cursor = M.MacroCursor;
SavedStreamPosition SavedPosition(Cursor);
unsigned N = NumUserInputs;
if (ValidateSystemInputs ||
- (HSOpts.ModulesValidateOncePerBuildSession && F.Kind == MK_Module))
+ (HSOpts.ModulesValidateOncePerBuildSession &&
+ F.Kind == MK_ImplicitModule))
N = NumInputs;
for (unsigned I = 0; I < N; ++I) {
break;
case IMPORTED_MODULES: {
- if (F.Kind != MK_Module) {
+ if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) {
// If we aren't loading a module (which has its own exports), make
// all of the imported modules visible.
// FIXME: Deal with macros-only imports.
unsigned Idx = 0;
F.ModuleMapPath = ReadString(Record, Idx);
+ if (F.Kind == MK_ExplicitModule) {
+ // For an explicitly-loaded module, we don't care whether the original
+ // module map file exists or matches.
+ return Success;
+ }
+
// Try to resolve ModuleName in the current header search context and
// verify that it is found in the same module map file as we saved. If the
// top-level AST file is a main file, skip this check because there is no
// usable header search context.
assert(!F.ModuleName.empty() &&
- "MODULE_NAME should come before MOUDLE_MAP_FILE");
- if (F.Kind == MK_Module && (*ModuleMgr.begin())->Kind != MK_MainFile) {
+ "MODULE_NAME should come before MODULE_MAP_FILE");
+ if (F.Kind == MK_ImplicitModule &&
+ (*ModuleMgr.begin())->Kind != MK_MainFile) {
+ // An implicitly-loaded module file should have its module listed in some
+ // module map file that we've already loaded.
Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
- if (!M) {
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr;
+ if (!ModMap) {
assert(ImportedBy && "top-level import should be verified");
if ((ClientLoadCapabilities & ARR_Missing) == 0)
- Diag(diag::err_imported_module_not_found)
- << F.ModuleName << ImportedBy->FileName;
+ Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName
+ << ImportedBy->FileName
+ << F.ModuleMapPath;
return Missing;
}
+ assert(M->Name == F.ModuleName && "found module with different name");
+
// Check the primary module map file.
- auto &Map = PP.getHeaderSearchInfo().getModuleMap();
const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath);
- const FileEntry *ModMap = Map.getModuleMapFileForUniquing(M);
if (StoredModMap == nullptr || StoredModMap != ModMap) {
assert(ModMap && "found module is missing module map file");
- assert(M->Name == F.ModuleName && "found module with different name");
assert(ImportedBy && "top-level import should be verified");
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
Diag(diag::err_imported_module_modmap_changed)
// in the filesystem).
for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
ImportedModule &M = Loaded[I];
- if (M.Mod->Kind == MK_Module) {
+ if (M.Mod->Kind == MK_ImplicitModule) {
updateModuleTimestamp(*M.Mod);
}
}
break;
case ModuleManager::Missing:
- // The module file was missing; if the client handle handle, that, return
+ // The module file was missing; if the client can handle that, return
// it.
if (ClientLoadCapabilities & ARR_Missing)
return Missing;
for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
++IDIdx) {
const PendingMacroInfo &Info = GlobalIDs[IDIdx];
- if (Info.M->Kind != MK_Module)
+ if (Info.M->Kind != MK_ImplicitModule &&
+ Info.M->Kind != MK_ExplicitModule)
resolvePendingMacro(II, Info);
}
// Handle module imports.
for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
++IDIdx) {
const PendingMacroInfo &Info = GlobalIDs[IDIdx];
- if (Info.M->Kind == MK_Module)
+ if (Info.M->Kind == MK_ImplicitModule ||
+ Info.M->Kind == MK_ExplicitModule)
resolvePendingMacro(II, Info);
}
}
// any other module's anonymous namespaces, so don't attach the anonymous
// namespace at all.
NamespaceDecl *Anon = ReadDeclAs<NamespaceDecl>(Record, Idx);
- if (F.Kind != MK_Module)
+ if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule)
D->setAnonymousNamespace(Anon);
} else {
// Link this namespace back to the first declaration, which has already
// Each module has its own anonymous namespace, which is disjoint from
// any other module's anonymous namespaces, so don't attach the anonymous
// namespace at all.
- if (ModuleFile.Kind != MK_Module) {
+ if (ModuleFile.Kind != MK_ImplicitModule &&
+ ModuleFile.Kind != MK_ExplicitModule) {
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
TU->setAnonymousNamespace(Anon);
else
ModuleEntry = New;
New->InputFilesValidationTimestamp = 0;
- if (New->Kind == MK_Module) {
+ if (New->Kind == MK_ImplicitModule) {
std::string TimestampFilename = New->getTimestampFilename();
vfs::Status Status;
// A cached stat value would be fine as well.
--- /dev/null
+#if !__building_module(a)
+#error "should only get here when building module a"
+#endif
+
+const int a = 1;
--- /dev/null
+#include "a.h"
+
+#if !__building_module(b)
+#error "should only get here when building module b"
+#endif
+
+const int b = 2;
--- /dev/null
+#include "b.h"
+
+#if !__building_module(c)
+#error "should only get here when building module c"
+#endif
+
+const int c = 3;
--- /dev/null
+module a { header "a.h" }
+module b { header "b.h" export * }
+module c { header "c.h" export * }
--- /dev/null
+// RUN: rm -rf %t
+
+// -------------------------------
+// Build chained modules A, B, and C
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -fmodule-name=c -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/c.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// CHECK-NO-IMPLICIT-BUILD-NOT: building module
+
+// -------------------------------
+// Build B with an implicit build of A
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b-not-a.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-B-NO-A %s
+//
+// CHECK-B-NO-A: While building module 'b':
+// CHECK-B-NO-A: building module 'a' as
+
+// -------------------------------
+// Check that we can use the explicitly-built A, B, and C modules.
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -verify %s -DHAVE_A
+//
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: -verify %s -DHAVE_A
+//
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B
+//
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B
+//
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -fmodule-file=%t/c.pcm \
+// RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C
+//
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b.pcm \
+// RUN: -fmodule-file=%t/c.pcm \
+// RUN: -verify %s -INCLUDE_ALL -DHAVE_A -DHAVE_B -DHAVE_C
+
+#ifdef INCLUDE_ALL
+ #include "a.h"
+ #include "b.h"
+ #include "c.h"
+ static_assert(a == 1, "");
+ static_assert(b == 2, "");
+ static_assert(c == 3, "");
+#else
+ const int use_a = a;
+ #ifndef HAVE_A
+ // expected-error@-2 {{undeclared identifier}}
+ #else
+ // expected-error@-4 {{must be imported from module 'a'}}
+ // expected-note@Inputs/explicit-build/a.h:* {{here}}
+ #endif
+
+ const int use_b = b;
+ #ifndef HAVE_B
+ // expected-error@-2 {{undeclared identifier}}
+ #else
+ // expected-error@-4 {{must be imported from module 'b'}}
+ // expected-note@Inputs/explicit-build/b.h:* {{here}}
+ #endif
+
+ const int use_c = c;
+ #ifndef HAVE_C
+ // expected-error@-2 {{undeclared identifier}}
+ #else
+ // expected-error@-4 {{must be imported from module 'c'}}
+ // expected-note@Inputs/explicit-build/c.h:* {{here}}
+ #endif
+#endif
+
+// -------------------------------
+// Check that we can use a mixture of implicit and explicit modules.
+// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/b-not-a.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s
+
+// -------------------------------
+// Check that mixing an implicit and explicit form of the 'a' module is rejected.
+// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b-not-a.pcm \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s
+//
+// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/b-not-a.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s
+//
+// FIXME: We should load module map files specified on the command line and
+// module map files in include paths on demand to allow this, and possibly
+// also the previous case.
+// CHECK-A-AND-B-NO-A: fatal error: module 'a' {{.*}} is not defined in any loaded module map
+
+// -------------------------------
+// Try to use two different flavors of the 'a' module.
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a-alt.pcm \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-file=%t/a-alt.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s
+//
+// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a-alt.pcm \
+// RUN: -fmodule-file=%t/a.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s
+//
+// CHECK-MULTIPLE-AS: error: module 'a' has already been loaded; cannot load module file '{{.*a(-alt)?}}.pcm'
+
+// -------------------------------
+// Try to import a PCH with -fmodule-file=
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-name=a -emit-pch %S/Inputs/explicit-build/a.h -o %t/a.pch \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty
+//
+// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/a.pch \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AS-PCH %s
+//
+// CHECK-A-AS-PCH: fatal error: AST file '{{.*}}a.pch' was not built as a module
// Use the PCH with no way to resolve DependsOnA
// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NODOA %s
-// CHECK-NODOA: module 'DependsOnA' imported by AST file '{{.*A.pch}}' not found
+// CHECK-NODOA: module 'DependsOnA' in AST file '{{.*DependsOnA.*pcm}}' (imported by AST file '{{.*A.pch}}') is not defined in any loaded module map
// Use the PCH with no way to resolve A
// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NOA %s
-// CHECK-NOA: module 'A' imported by AST file '{{.*DependsOnA.*pcm}}' not found
+// CHECK-NOA: module 'A' in AST file '{{.*A.*pcm}}' (imported by AST file '{{.*DependsOnA.*pcm}}') is not defined in any loaded module map
// Use the PCH and have it resolve the the other A
// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path2/A -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-WRONGA %s