]> granicus.if.org Git - clang/commitdiff
[modules] If we hit a failure while loading a PCH/module, abort parsing instead of...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 24 May 2013 05:44:08 +0000 (05:44 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 24 May 2013 05:44:08 +0000 (05:44 +0000)
Also don't let libclang create a PCH with such an error.

Fixes rdar://13953768

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

13 files changed:
include/clang/Frontend/ASTUnit.h
include/clang/Frontend/CompilerInstance.h
include/clang/Lex/ModuleLoader.h
include/clang/Lex/Preprocessor.h
include/clang/Parse/Parser.h
include/clang/Serialization/ASTReader.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/CompilerInstance.cpp
lib/Lex/Lexer.cpp
lib/Lex/PPDirectives.cpp
lib/Parse/Parser.cpp
lib/Serialization/ASTReader.cpp
test/Modules/fatal-module-loader-error.m [new file with mode: 0644]

index 1fc56ce5f3ca22be61c2157ee7c4c4101db0ddd1..c915776963e0f4a2d4e37a3bcacdab392f7e4c1d 100644 (file)
@@ -75,6 +75,7 @@ private:
   IntrusiveRefCntPtr<TargetOptions>       TargetOpts;
   IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
   ASTReader *Reader;
+  bool HadModuleLoaderFatalFailure;
 
   struct ASTWriterData;
   OwningPtr<ASTWriterData> WriterData;
index ee4850580d660936704efbb2960f27ec4f3acda3..3ad05a651087a4727a1215110a8a21caea55b353 100644 (file)
@@ -664,6 +664,10 @@ public:
                                  SourceLocation ImportLoc,
                                  bool Complain);
 
+  bool hadModuleLoaderFatalFailure() const {
+    return ModuleLoader::HadFatalFailure;
+  }
+
 };
 
 } // end namespace clang
index 3acf9151bc52b1a30dbdb7ada512defb575da612..254ab36fe9607f0a7892c19ac675f2a516b9519d 100644 (file)
@@ -54,6 +54,8 @@ public:
 /// then loading that module.
 class ModuleLoader {
 public:
+  ModuleLoader() : HadFatalFailure(false) {}
+
   virtual ~ModuleLoader();
   
   /// \brief Attempt to load the given module.
@@ -85,6 +87,8 @@ public:
                                  Module::NameVisibilityKind Visibility,
                                  SourceLocation ImportLoc,
                                  bool Complain) = 0;
+
+  bool HadFatalFailure;
 };
   
 }
index e70eaa8fc8607bbbd04c5a3937d6db1742397945..082f4e4cdeb7d0f7fccb1c853940709512676a75 100644 (file)
@@ -457,6 +457,10 @@ public:
   /// \brief Retrieve the module loader associated with this preprocessor.
   ModuleLoader &getModuleLoader() const { return TheModuleLoader; }
 
+  bool hadModuleLoaderFatalFailure() const {
+    return TheModuleLoader.HadFatalFailure;
+  }
+
   /// \brief True if we are currently preprocessing a #if or #elif directive
   bool isParsingIfOrElifDirective() const { 
     return ParsingIfOrElifDirective;
index 5a5b0669b205a21cca93111ce19cdf517a1f4089..de45268e0482e69953c4e7024b58d79a942ecb26 100644 (file)
@@ -398,7 +398,8 @@ private:
   /// \brief Abruptly cut off parsing; mainly used when we have reached the
   /// code-completion point.
   void cutOffParsing() {
-    PP.setCodeCompletionReached();
+    if (PP.isCodeCompletionEnabled())
+      PP.setCodeCompletionReached();
     // Cut off parsing by acting as if we reached the end-of-file.
     Tok.setKind(tok::eof);
   }
index 073baf514cd3bc779342a8f8c9037024a2f19407..3861b8f67cc9cf7a76c7d1e70945825e7f162e21 100644 (file)
@@ -309,6 +309,10 @@ private:
   /// \brief The module manager which manages modules and their dependencies
   ModuleManager ModuleMgr;
 
+  /// \brief The location where the module file will be considered as
+  /// imported from. For non-module AST types it should be invalid.
+  SourceLocation CurrentImportLoc;
+
   /// \brief The global module index, if loaded.
   llvm::OwningPtr<GlobalModuleIndex> GlobalIndex;
 
index 7850dc697be498a944fcab9ce45423b59fba1766..2d916536d3d2f75fc5d65dc8573224b9060f7a22 100644 (file)
@@ -216,7 +216,8 @@ const unsigned DefaultPreambleRebuildInterval = 5;
 static llvm::sys::cas_flag ActiveASTUnitObjects;
 
 ASTUnit::ASTUnit(bool _MainFileIsAST)
-  : Reader(0), OnlyLocalDecls(false), CaptureDiagnostics(false),
+  : Reader(0), HadModuleLoaderFatalFailure(false),
+    OnlyLocalDecls(false), CaptureDiagnostics(false),
     MainFileIsAST(_MainFileIsAST), 
     TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
     OwnsRemappedFileBuffers(true),
@@ -1705,6 +1706,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
   CI.setFileManager(0);
   Target = &CI.getTarget();
   Reader = CI.getModuleManager();
+  HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
 }
 
 StringRef ASTUnit::getMainFileName() const {
@@ -2504,6 +2506,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
 }
 
 bool ASTUnit::Save(StringRef File) {
+  if (HadModuleLoaderFatalFailure)
+    return true;
+
   // Write to a temporary file and later rename it to the actual file, to avoid
   // possible race conditions.
   SmallString<128> TempPath;
index cf856fc2ab6525ad53d87505ce36e4ec54cb7e10..b4bb6f325170767f3564531728755fe4a07d9c25 100644 (file)
@@ -1247,12 +1247,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
     case ASTReader::VersionMismatch:
     case ASTReader::ConfigurationMismatch:
     case ASTReader::HadErrors:
+      ModuleLoader::HadFatalFailure = true;
       // FIXME: The ASTReader will already have complained, but can we showhorn
       // that diagnostic information into a more useful form?
       KnownModules[Path[0].first] = 0;
       return ModuleLoadResult();
 
     case ASTReader::Failure:
+      ModuleLoader::HadFatalFailure = true;
       // Already complained, but note now that we failed.
       KnownModules[Path[0].first] = 0;
       ModuleBuildFailed = true;
index e58581ee06ba766e8088967a6d9fd809d7886ecd..e3daf346926f5c974b02447a3c96d3d9c71795de 100644 (file)
@@ -3426,6 +3426,12 @@ HandleDirective:
   FormTokenWithChars(Result, CurPtr, tok::hash);
   PP->HandleDirective(Result);
 
+  if (PP->hadModuleLoaderFatalFailure()) {
+    // With a fatal failure in the module loader, we abort parsing.
+    assert(Result.is(tok::eof) && "Preprocessor did not set tok:eof");
+    return;
+  }
+
   // As an optimization, if the preprocessor didn't switch lexers, tail
   // recurse.
   if (PP->isCurrentLexer(this)) {
index ba3291aa398dad2123a0f9ecad20994c66521029..947011d7075847587f04f633e8a0c67aaf9b643d 100644 (file)
@@ -1512,6 +1512,20 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
                                    /*IsIncludeDirective=*/true);
     assert((Imported == 0 || Imported == SuggestedModule) &&
            "the imported module is different than the suggested one");
+
+    if (!Imported && hadModuleLoaderFatalFailure()) {
+      // With a fatal failure in the module loader, we abort parsing.
+      Token &Result = IncludeTok;
+      if (CurLexer) {
+        Result.startToken();
+        CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof);
+        CurLexer->cutOffLexing();
+      } else {
+        assert(CurPTHLexer && "#include but no current lexer set!");
+        CurPTHLexer->getEOF(Result);
+      }
+      return;
+    }
     
     // If this header isn't part of the module we're building, we're done.
     if (!BuildingImportedModule && Imported) {
index a5371f9e61228652343af3a569709aa8356c97c5..3124b96455e2e95b644703c0fa7da8ae3812b793 100644 (file)
@@ -1884,7 +1884,13 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
     
     break;
   } while (true);
-  
+
+  if (PP.hadModuleLoaderFatalFailure()) {
+    // With a fatal failure in the module loader, we abort parsing.
+    cutOffParsing();
+    return DeclGroupPtrTy();
+  }
+
   DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path);
   ExpectAndConsumeSemi(diag::err_module_expected_semi);
   if (Import.isInvalid())
index 17f01380ed04ea7696beea6f4fd2a4985a32a13b..a4c8c353077cdb73265332570342cd4e379bee21 100644 (file)
@@ -2900,6 +2900,9 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
                                             ModuleKind Type,
                                             SourceLocation ImportLoc,
                                             unsigned ClientLoadCapabilities) {
+  llvm::SaveAndRestore<SourceLocation>
+    SetCurImportLocRAII(CurrentImportLoc, ImportLoc);
+
   // Bump the generation number.
   unsigned PreviousGeneration = CurrentGeneration++;
 
@@ -7167,7 +7170,7 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
 }
 
 DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
-  return Diag(SourceLocation(), DiagID);
+  return Diag(CurrentImportLoc, DiagID);
 }
 
 DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
diff --git a/test/Modules/fatal-module-loader-error.m b/test/Modules/fatal-module-loader-error.m
new file mode 100644 (file)
index 0000000..acfc539
--- /dev/null
@@ -0,0 +1,26 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: touch %t/Module.pcm
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -fdisable-module-hash -F %S/Inputs -verify
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -fdisable-module-hash -F %S/Inputs -DIMPLICIT -verify
+
+// This tests that after a fatal module loader error, we do not continue parsing.
+
+#ifdef IMPLICIT
+
+// expected-error@+1{{does not appear to be}}
+#import <Module/Module.h>
+#pragma clang __debug crash;
+
+#else
+
+// expected-error@+1{{does not appear to be}}
+@import Module;
+#pragma clang __debug crash;
+
+#endif
+
+// Also check that libclang does not create a PCH with such an error.
+// RUN: c-index-test -write-pch %t.pch -fmodules -fmodules-cache-path=%t %s \
+// RUN:    -Xclang -fdisable-module-hash -F %S/Inputs 2>&1 | Filecheck %s
+// CHECK: Unable to write PCH file