]> granicus.if.org Git - clang/commitdiff
Revert r288626, which reverts r288449. Original commit message:
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 6 Dec 2016 00:40:17 +0000 (00:40 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 6 Dec 2016 00:40:17 +0000 (00:40 +0000)
Recover better from an incompatible .pcm file being provided by -fmodule-file=. We try to include the headers of the module textually in this case, still enforcing the modules semantic rules. In order to make that work, we need to still track that we're entering and leaving the module. Also, if the module was also marked as unavailable (perhaps because it was missing a file), we shouldn't mark the module unavailable -- we don't need the module to be complete if we're going to enter it textually.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@288741 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Lex/ModuleLoader.h
lib/Frontend/CompilerInstance.cpp
lib/Lex/PPDirectives.cpp
test/Modules/config-mismatch.cpp [new file with mode: 0644]

index ae79650d1fd0b7744ef8cf00aa383ecb6a50d904..70770d17e9ffa4abb0fc048315afc1dbe15b38cc 100644 (file)
@@ -31,13 +31,22 @@ typedef ArrayRef<std::pair<IdentifierInfo *, SourceLocation> > ModuleIdPath;
 
 /// \brief Describes the result of attempting to load a module.
 class ModuleLoadResult {
-  llvm::PointerIntPair<Module *, 1, bool> Storage;
-
 public:
-  ModuleLoadResult() : Storage() { }
+  enum LoadResultKind {
+    // We either succeeded or failed to load the named module.
+    Normal,
+    // The module exists, but does not actually contain the named submodule.
+    // This should only happen if the named submodule was inferred from an
+    // umbrella directory, but not actually part of the umbrella header.
+    MissingExpected,
+    // The module exists but cannot be imported due to a configuration mismatch.
+    ConfigMismatch
+  };
+  llvm::PointerIntPair<Module *, 2, LoadResultKind> Storage;
 
-  ModuleLoadResult(Module *module, bool missingExpected)
-    : Storage(module, missingExpected) { }
+  ModuleLoadResult() : Storage() { }
+  ModuleLoadResult(Module *M) : Storage(M, Normal) {}
+  ModuleLoadResult(LoadResultKind Kind) : Storage(nullptr, Kind) {}
 
   operator Module *() const { return Storage.getPointer(); }
 
@@ -45,7 +54,11 @@ public:
   /// actually a submodule that we expected to see (based on implying the
   /// submodule from header structure), but didn't materialize in the actual
   /// module.
-  bool isMissingExpected() const { return Storage.getInt(); }
+  bool isMissingExpected() const { return Storage.getInt() == MissingExpected; }
+
+  /// \brief Determines whether the module failed to load due to a configuration
+  /// mismatch with an explicitly-named .pcm file from the command line.
+  bool isConfigMismatch() const { return Storage.getInt() == ConfigMismatch; }
 };
 
 /// \brief Abstract interface for a module loader.
index d314f6d18a6198529b160979137d53db9511a836..991e9ef990a0bce6a4206587382929cec0a13d6c 100644 (file)
@@ -1393,8 +1393,21 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
         if (Module *M = CI.getPreprocessor()
                             .getHeaderSearchInfo()
                             .getModuleMap()
-                            .findModule(II->getName()))
+                            .findModule(II->getName())) {
           M->HasIncompatibleModuleFile = true;
+
+          // Mark module as available if the only reason it was unavailable
+          // was missing headers.
+          SmallVector<Module *, 2> Stack;
+          Stack.push_back(M);
+          while (!Stack.empty()) {
+            Module *Current = Stack.pop_back_val();
+            if (Current->IsMissingRequirement) continue;
+            Current->IsAvailable = true;
+            Stack.insert(Stack.end(),
+                         Current->submodule_begin(), Current->submodule_end());
+          }
+        }
       }
       LoadedModules.clear();
     }
@@ -1498,7 +1511,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
       if (Module && Module->HasIncompatibleModuleFile) {
         // We tried and failed to load a module file for this module. Fall
         // back to textual inclusion for its headers.
-        return ModuleLoadResult(nullptr, /*missingExpected*/true);
+        return ModuleLoadResult::ConfigMismatch;
       }
 
       getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled)
@@ -1705,7 +1718,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
         << Module->getFullModuleName()
         << SourceRange(Path.front().second, Path.back().second);
 
-      return ModuleLoadResult(nullptr, true);
+      return ModuleLoadResult::MissingExpected;
     }
 
     // Check whether this module is available.
@@ -1739,7 +1752,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
   }
 
   LastModuleImportLoc = ImportLoc;
-  LastModuleImportResult = ModuleLoadResult(Module, false);
+  LastModuleImportResult = ModuleLoadResult(Module);
   return LastModuleImportResult;
 }
 
index 7fc008274bdb4f2ba671be6015e81e90bdcb93ec..85504de3d15d864eefe996f922f19ded13ef2741 100644 (file)
@@ -1866,10 +1866,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
     // unavailable, diagnose the situation and bail out.
     // FIXME: Remove this; loadModule does the same check (but produces
     // slightly worse diagnostics).
-    if (!SuggestedModule.getModule()->isAvailable() &&
-        !SuggestedModule.getModule()
-             ->getTopLevelModule()
-             ->HasIncompatibleModuleFile) {
+    if (!SuggestedModule.getModule()->isAvailable()) {
       Module::Requirement Requirement;
       Module::UnresolvedHeaderDirective MissingHeader;
       Module *M = SuggestedModule.getModule();
@@ -1918,9 +1915,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
     else if (Imported.isMissingExpected()) {
       // We failed to find a submodule that we assumed would exist (because it
       // was in the directory of an umbrella header, for instance), but no
-      // actual module exists for it (because the umbrella header is
+      // actual module containing it exists (because the umbrella header is
       // incomplete).  Treat this as a textual inclusion.
       SuggestedModule = ModuleMap::KnownHeader();
+    } else if (Imported.isConfigMismatch()) {
+      // On a configuration mismatch, enter the header textually. We still know
+      // that it's part of the corresponding module.
     } else {
       // We hit an error processing the import. Bail out.
       if (hadModuleLoaderFatalFailure()) {
diff --git a/test/Modules/config-mismatch.cpp b/test/Modules/config-mismatch.cpp
new file mode 100644 (file)
index 0000000..9ddc513
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'module M { header "foo.h" header "bar.h" }' > %t/map
+// RUN: echo 'template<typename T> void f(T t) { int n; t.f(n); }' > %t/foo.h
+// RUN: touch %t/bar.h
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -x c++ %t/map -emit-module -fmodule-name=M -o %t/pcm
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-map-file=%t/map -fmodule-file=%t/pcm -I%t %s -fsyntax-only -fexceptions -Wno-module-file-config-mismatch -verify
+// RUN: rm %t/bar.h
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-map-file=%t/map -fmodule-file=%t/pcm -I%t %s -fsyntax-only -fexceptions -Wno-module-file-config-mismatch -verify
+#include "foo.h"
+namespace n { // expected-note {{begins here}}
+#include "foo.h" // expected-error {{redundant #include of module 'M' appears within namespace}}
+}