}
}
-ModuleLoadResult
-CompilerInstance::loadModuleFile(StringRef FileName, SourceLocation Loc) {
- if (!ModuleManager)
- createModuleManager();
- if (!ModuleManager)
- return ModuleLoadResult();
+bool CompilerInstance::loadModuleFile(StringRef FileName) {
+ // Helper to recursively read the module names for all modules we're adding.
+ // We mark these as known and redirect any attempt to load that module to
+ // the files we were handed.
+ struct ReadModuleNames : ASTReaderListener {
+ CompilerInstance &CI;
+ std::vector<StringRef> ModuleFileStack;
+ bool Failed;
+ bool TopFileIsModule;
+
+ ReadModuleNames(CompilerInstance &CI)
+ : CI(CI), Failed(false), TopFileIsModule(false) {}
+
+ bool needsImportVisitation() const override { return true; }
+
+ void visitImport(StringRef FileName) override {
+ ModuleFileStack.push_back(FileName);
+ if (ASTReader::readASTFileControlBlock(FileName, CI.getFileManager(),
+ *this)) {
+ CI.getDiagnostics().Report(SourceLocation(),
+ diag::err_module_file_not_found)
+ << FileName;
+ // FIXME: Produce a note stack explaining how we got here.
+ Failed = true;
+ }
+ ModuleFileStack.pop_back();
+ }
- // 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();
+ void ReadModuleName(StringRef ModuleName) override {
+ if (ModuleFileStack.size() == 1)
+ TopFileIsModule = true;
- MF = ModuleManager->getModuleManager().lookup(FileName);
- assert(MF && "unexpectedly failed to load module file");
- }
+ auto &ModuleFile = CI.ModuleFileOverrides[ModuleName];
+ if (!ModuleFile.empty() && ModuleFile != ModuleFileStack.back())
+ CI.getDiagnostics().Report(SourceLocation(),
+ diag::err_conflicting_module_files)
+ << ModuleName << ModuleFile << ModuleFileStack.back();
+ ModuleFile = ModuleFileStack.back();
+ }
+ } RMN(*this);
+
+ RMN.visitImport(FileName);
- if (MF->ModuleName.empty()) {
- getDiagnostics().Report(Loc, diag::err_module_file_not_module)
+ if (RMN.Failed)
+ return false;
+
+ // If we never found a module name for the top file, then it's not a module,
+ // it's a PCH or preamble or something.
+ if (!RMN.TopFileIsModule) {
+ getDiagnostics().Report(SourceLocation(), diag::err_module_file_not_module)
<< FileName;
- return ModuleLoadResult();
+ return false;
}
- auto *Module = PP->getHeaderSearchInfo().lookupModule(MF->ModuleName, false);
- return ModuleLoadResult(Module, false);
+
+ return true;
}
ModuleLoadResult
return ModuleLoadResult();
}
+ auto Override = ModuleFileOverrides.find(ModuleName);
+ bool Explicit = Override != ModuleFileOverrides.end();
+
std::string ModuleFileName =
- PP->getHeaderSearchInfo().getModuleFileName(Module);
+ Explicit ? Override->second
+ : PP->getHeaderSearchInfo().getModuleFileName(Module);
// If we don't already have an ASTReader, create one now.
if (!ModuleManager)
Listener->attachToASTReader(*ModuleManager);
// Try to load the module file.
- unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ unsigned ARRFlags =
+ Explicit ? 0 : ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
switch (ModuleManager->ReadAST(ModuleFileName,
- serialization::MK_ImplicitModule, ImportLoc,
- ARRFlags)) {
+ Explicit ? serialization::MK_ExplicitModule
+ : serialization::MK_ImplicitModule,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success:
break;
case ASTReader::OutOfDate:
case ASTReader::Missing: {
+ if (Explicit) {
+ // ReadAST has already complained for us.
+ ModuleLoader::HadFatalFailure = true;
+ KnownModules[Path[0].first] = nullptr;
+ return ModuleLoadResult();
+ }
+
// The module file is missing or out-of-date. Build it.
assert(Module && "missing module file");
// Check whether there is a cycle in the module graph.
// -------------------------------
// Build chained modules A, B, and C
-// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: %clang_cc1 -x c++ -std=c++11 -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: %clang_cc1 -x c++ -std=c++11 -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: %clang_cc1 -x c++ -std=c++11 -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
// -------------------------------
// 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: %clang_cc1 -x c++ -std=c++11 -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 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: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
// 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: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \
+// 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: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
// 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: %clang_cc1 -x c++ -std=c++11 -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: -verify %s -DHAVE_A -DHAVE_B
//
-// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: %clang_cc1 -x c++ -std=c++11 -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 -DHAVE_A -DHAVE_B -DHAVE_C
//
-// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: %clang_cc1 -x c++ -std=c++11 -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
+// RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C
-#ifdef INCLUDE_ALL
+#if HAVE_A
#include "a.h"
- #include "b.h"
- #include "c.h"
static_assert(a == 1, "");
+#else
+ const int use_a = a; // expected-error {{undeclared identifier}}
+#endif
+
+#if HAVE_B
+ #include "b.h"
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; // expected-error {{undeclared identifier}}
+#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
+#if HAVE_C
+ #include "c.h"
+ static_assert(c == 3, "");
+#else
+ const int use_c = c; // expected-error {{undeclared identifier}}
+#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
+#if HAVE_A && HAVE_B && HAVE_C
+// expected-no-diagnostics
#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: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -I%S/Inputs/explicit-build \
// 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
+// RUN: -verify %s -DHAVE_A -DHAVE_B
// -------------------------------
-// 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 \
+// Try to use two different flavors of the 'a' module.
+// RUN: not %clang_cc1 -x c++ -std=c++11 -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: %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: not %clang_cc1 -x c++ -std=c++11 -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
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %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: %clang_cc1 -x c++ -std=c++11 -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: not %clang_cc1 -x c++ -std=c++11 -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: not %clang_cc1 -x c++ -std=c++11 -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'
+// CHECK-MULTIPLE-AS: error: module 'a' is defined in both '{{.*}}/a{{.*}}.pcm' and '{{.*}}/a{{.*}}.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: %clang_cc1 -x c++ -std=c++11 -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: not %clang_cc1 -x c++ -std=c++11 -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
+
+// -------------------------------
+// Try to import a non-AST file with -fmodule-file=
+//
+// RUN: touch %t/not.pcm
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/not.pcm \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-BAD-FILE %s
+//
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \
+// RUN: -fmodule-file=%t/nonexistent.pcm \
+// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-BAD-FILE %s
+//
+// CHECK-BAD-FILE: fatal error: file '{{.*}}t.pcm' is not a precompiled module file