erikjv created this revision.
erikjv added reviewers: klimek, rsmith.
erikjv added a subscriber: cfe-commits.

When generating pre-compiled headers, or when opening a header file with
libclang, suppress the warnings "#pragma once in main file" and
"#include_next in primary source file".
    
Fixes PR16686 and PR24390.


http://reviews.llvm.org/D15926

Files:
  include/clang/Basic/SourceManager.h
  include/clang/Frontend/FrontendOptions.h
  lib/Frontend/CompilerInstance.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Frontend/FrontendActions.cpp
  lib/Lex/PPDirectives.cpp
  lib/Lex/PPMacroExpansion.cpp
  lib/Lex/Pragma.cpp
  test/Preprocessor/header_is_main_file.c

Index: test/Preprocessor/header_is_main_file.c
===================================================================
--- /dev/null
+++ test/Preprocessor/header_is_main_file.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -x c-header -ffreestanding -Eonly -verify %s
+// expected-no-diagnostics
+
+#pragma once
+#include_next "stdint.h"
+#if !__has_include_next("stdint.h")
+#error "__has_include_next failed"
+#endif
Index: lib/Lex/Pragma.cpp
===================================================================
--- lib/Lex/Pragma.cpp
+++ lib/Lex/Pragma.cpp
@@ -354,7 +354,9 @@
 /// HandlePragmaOnce - Handle \#pragma once.  OnceTok is the 'once'.
 ///
 void Preprocessor::HandlePragmaOnce(Token &OnceTok) {
-  if (isInPrimaryFile()) {
+  // If the main file is a header, then it's either for PCH/AST generation,
+  // or libclang opened it. Allow #pragma once either way.
+  if (isInPrimaryFile() && !SourceMgr.isMainFileHeader()) {
     Diag(OnceTok, diag::pp_pragma_once_in_main_file);
     return;
   }
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -1389,7 +1389,10 @@
   // Preprocessor::HandleIncludeNextDirective.
   const DirectoryLookup *Lookup = PP.GetCurDirLookup();
   const FileEntry *LookupFromFile = nullptr;
-  if (PP.isInPrimaryFile()) {
+  if (PP.isInPrimaryFile() && PP.getSourceManager().isMainFileHeader()) {
+    // If the main file is a header, then it's either for PCH/AST generation,
+    // or libclang opened it. Either way, handle it as a normal include below.
+  } else if (PP.isInPrimaryFile()) {
     Lookup = nullptr;
     PP.Diag(Tok, diag::pp_include_next_in_primary);
   } else if (PP.getCurrentSubmodule()) {
Index: lib/Lex/PPDirectives.cpp
===================================================================
--- lib/Lex/PPDirectives.cpp
+++ lib/Lex/PPDirectives.cpp
@@ -1834,7 +1834,10 @@
   // diagnostic.
   const DirectoryLookup *Lookup = CurDirLookup;
   const FileEntry *LookupFromFile = nullptr;
-  if (isInPrimaryFile()) {
+  if (isInPrimaryFile() && SourceMgr.isMainFileHeader()) {
+    // If the main file is a header, then it's either for PCH/AST generation,
+    // or libclang opened it. Either way, handle it as a normal include below.
+  } else if (isInPrimaryFile()) {
     Lookup = nullptr;
     Diag(IncludeNextTok, diag::pp_include_next_in_primary);
   } else if (CurSubmodule) {
Index: lib/Frontend/FrontendActions.cpp
===================================================================
--- lib/Frontend/FrontendActions.cpp
+++ lib/Frontend/FrontendActions.cpp
@@ -375,7 +375,7 @@
                                            Module::getModuleInputBufferName());
   // Ownership of InputBuffer will be transferred to the SourceManager.
   setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(),
-                                    Module->IsSystem));
+                                    false, Module->IsSystem));
   return true;
 }
 
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1141,6 +1141,7 @@
   }
 
   InputKind DashX = IK_None;
+  bool IsHeader = false;
   if (const Arg *A = Args.getLastArg(OPT_x)) {
     DashX = llvm::StringSwitch<InputKind>(A->getValue())
       .Case("c", IK_C)
@@ -1168,6 +1169,13 @@
     if (DashX == IK_None)
       Diags.Report(diag::err_drv_invalid_value)
         << A->getAsString(Args) << A->getValue();
+    IsHeader = llvm::StringSwitch<bool>(A->getValue())
+        .Case("c-header", true)
+        .Case("cl-header", true)
+        .Case("objective-c-header", true)
+        .Case("c++-header", true)
+        .Case("objective-c++-header", true)
+        .Default(false);
   }
 
   // '-' is the default input if none is given.
@@ -1184,7 +1192,7 @@
       if (i == 0)
         DashX = IK;
     }
-    Opts.Inputs.emplace_back(std::move(Inputs[i]), IK);
+    Opts.Inputs.emplace_back(std::move(Inputs[i]), IK, IsHeader);
   }
 
   return DashX;
Index: lib/Frontend/CompilerInstance.cpp
===================================================================
--- lib/Frontend/CompilerInstance.cpp
+++ lib/Frontend/CompilerInstance.cpp
@@ -724,6 +724,7 @@
                                                const FrontendOptions &Opts) {
   SrcMgr::CharacteristicKind
     Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
+  SourceMgr.setMainFileHeader(Input.isHeader());
 
   if (Input.isBuffer()) {
     SourceMgr.setMainFileID(SourceMgr.createFileID(
Index: include/clang/Frontend/FrontendOptions.h
===================================================================
--- include/clang/Frontend/FrontendOptions.h
+++ include/clang/Frontend/FrontendOptions.h
@@ -88,18 +88,23 @@
   /// \brief The kind of input, e.g., C source, AST file, LLVM IR.
   InputKind Kind;
 
+  bool IsHeader;
+
   /// \brief Whether we're dealing with a 'system' input (vs. a 'user' input).
   bool IsSystem;
 
 public:
   FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { }
-  FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false)
-    : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { }
-  FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind,
+  FrontendInputFile(StringRef File, InputKind Kind, bool IsHeader = false,
                     bool IsSystem = false)
-    : Buffer(buffer), Kind(Kind), IsSystem(IsSystem) { }
+    : File(File.str()), Buffer(nullptr), Kind(Kind), IsHeader(IsHeader)
+    , IsSystem(IsSystem) { }
+  FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind,
+                    bool IsHeader = false, bool IsSystem = false)
+    : Buffer(buffer), Kind(Kind), IsHeader(IsHeader), IsSystem(IsSystem) { }
 
   InputKind getKind() const { return Kind; }
+  bool isHeader() const { return IsHeader; }
   bool isSystem() const { return IsSystem; }
 
   bool isEmpty() const { return File.empty() && Buffer == nullptr; }
Index: include/clang/Basic/SourceManager.h
===================================================================
--- include/clang/Basic/SourceManager.h
+++ include/clang/Basic/SourceManager.h
@@ -657,6 +657,8 @@
   /// \brief The file ID for the main source file of the translation unit.
   FileID MainFileID;
 
+  bool MainFileIsHeader = false;
+
   /// \brief The file ID for the precompiled preamble there is one.
   FileID PreambleFileID;
 
@@ -759,6 +761,14 @@
     MainFileID = FID;
   }
 
+  void setMainFileHeader(bool mainFileIsHeader) {
+    MainFileIsHeader = mainFileIsHeader;
+  }
+
+  bool isMainFileHeader() const {
+    return MainFileIsHeader;
+  }
+
   /// \brief Set the file ID for the precompiled preamble.
   void setPreambleFileID(FileID Preamble) {
     assert(PreambleFileID.isInvalid() && "PreambleFileID already set!");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to