]> granicus.if.org Git - clang/commitdiff
[-E] Emit a rewritten _Pragma on its own line.
authorJordan Rose <jordan_rose@apple.com>
Fri, 15 Jun 2012 23:33:51 +0000 (23:33 +0000)
committerJordan Rose <jordan_rose@apple.com>
Fri, 15 Jun 2012 23:33:51 +0000 (23:33 +0000)
1. Teach Lexer that pragma lexers are like macro expansions at EOF.
2. Treat pragmas like #define/#undef when printing.
3. If we just printed a directive, add a newline before any more tokens.
(4. Miscellaneous cleanup in PrintPreprocessedOutput.cpp)

PR10594 and <rdar://problem/11562490> (two separate related problems)

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

lib/Frontend/PrintPreprocessedOutput.cpp
lib/Lex/Lexer.cpp
test/Lexer/pragma-operators.cpp
test/Preprocessor/_Pragma-location.c
test/Preprocessor/comment_save.c

index 9e1587c8fa2f5f91aceb5fdef57612a3d3eba0c8..7e0bc6bb2d043dbbbc7a65f710e574a5cd8bc982 100644 (file)
@@ -87,7 +87,7 @@ private:
   unsigned CurLine;
 
   bool EmittedTokensOnThisLine;
-  bool EmittedMacroOnThisLine;
+  bool EmittedDirectiveOnThisLine;
   SrcMgr::CharacteristicKind FileType;
   SmallString<512> CurFilename;
   bool Initialized;
@@ -103,7 +103,7 @@ public:
     CurLine = 0;
     CurFilename += "<uninit>";
     EmittedTokensOnThisLine = false;
-    EmittedMacroOnThisLine = false;
+    EmittedDirectiveOnThisLine = false;
     FileType = SrcMgr::C_User;
     Initialized = false;
 
@@ -111,10 +111,15 @@ public:
     UseLineDirective = PP.getLangOpts().MicrosoftExt;
   }
 
-  void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
+  void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
   bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
 
-  bool StartNewLineIfNeeded();
+  void setEmittedDirectiveOnThisLine() { EmittedDirectiveOnThisLine = true; }
+  bool hasEmittedDirectiveOnThisLine() const {
+    return EmittedDirectiveOnThisLine;
+  }
+
+  bool startNewLineIfNeeded(bool ShouldUpdateCurrentLine = true);
   
   virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
                            SrcMgr::CharacteristicKind FileType,
@@ -158,11 +163,7 @@ public:
 void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
                                              const char *Extra,
                                              unsigned ExtraLen) {
-  if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) {
-    OS << '\n';
-    EmittedTokensOnThisLine = false;
-    EmittedMacroOnThisLine = false;
-  }
+  startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
 
   // Emit #line directives or GNU line markers depending on what mode we're in.
   if (UseLineDirective) {
@@ -207,23 +208,21 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
   } else {
     // Okay, we're in -P mode, which turns off line markers.  However, we still
     // need to emit a newline between tokens on different lines.
-    if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) {
-      OS << '\n';
-      EmittedTokensOnThisLine = false;
-      EmittedMacroOnThisLine = false;
-    }
+    startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
   }
 
   CurLine = LineNo;
   return true;
 }
 
-bool PrintPPOutputPPCallbacks::StartNewLineIfNeeded() {
-  if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) {
+bool
+PrintPPOutputPPCallbacks::startNewLineIfNeeded(bool ShouldUpdateCurrentLine) {
+  if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {
     OS << '\n';
     EmittedTokensOnThisLine = false;
-    EmittedMacroOnThisLine = false;
-    ++CurLine;
+    EmittedDirectiveOnThisLine = false;
+    if (ShouldUpdateCurrentLine)
+      ++CurLine;
     return true;
   }
   
@@ -307,7 +306,7 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
 
   MoveToLine(MI->getDefinitionLoc());
   PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS);
-  EmittedMacroOnThisLine = true;
+  setEmittedDirectiveOnThisLine();
 }
 
 void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
@@ -317,12 +316,13 @@ void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
 
   MoveToLine(MacroNameTok.getLocation());
   OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName();
-  EmittedMacroOnThisLine = true;
+  setEmittedDirectiveOnThisLine();
 }
 
 void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
                                              const IdentifierInfo *Kind,
                                              const std::string &Str) {
+  startNewLineIfNeeded();
   MoveToLine(Loc);
   OS << "#pragma comment(" << Kind->getName();
 
@@ -343,11 +343,12 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
   }
 
   OS << ')';
-  EmittedTokensOnThisLine = true;
+  setEmittedDirectiveOnThisLine();
 }
 
 void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
                                              StringRef Str) {
+  startNewLineIfNeeded();
   MoveToLine(Loc);
   OS << "#pragma message(";
 
@@ -366,26 +367,29 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
   OS << '"';
 
   OS << ')';
-  EmittedTokensOnThisLine = true;
+  setEmittedDirectiveOnThisLine();
 }
 
 void PrintPPOutputPPCallbacks::
 PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) {
+  startNewLineIfNeeded();
   MoveToLine(Loc);
   OS << "#pragma " << Namespace << " diagnostic push";
-  EmittedTokensOnThisLine = true;
+  setEmittedDirectiveOnThisLine();
 }
 
 void PrintPPOutputPPCallbacks::
 PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) {
+  startNewLineIfNeeded();
   MoveToLine(Loc);
   OS << "#pragma " << Namespace << " diagnostic pop";
-  EmittedTokensOnThisLine = true;
+  setEmittedDirectiveOnThisLine();
 }
 
 void PrintPPOutputPPCallbacks::
 PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
                  diag::Mapping Map, StringRef Str) {
+  startNewLineIfNeeded();
   MoveToLine(Loc);
   OS << "#pragma " << Namespace << " diagnostic ";
   switch (Map) {
@@ -403,7 +407,7 @@ PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
     break;
   }
   OS << " \"" << Str << '"';
-  EmittedTokensOnThisLine = true;
+  setEmittedDirectiveOnThisLine();
 }
 
 /// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
@@ -471,10 +475,9 @@ struct UnknownPragmaHandler : public PragmaHandler {
                             Token &PragmaTok) {
     // Figure out what line we went to and insert the appropriate number of
     // newline characters.
-    Callbacks->StartNewLineIfNeeded();
+    Callbacks->startNewLineIfNeeded();
     Callbacks->MoveToLine(PragmaTok.getLocation());
     Callbacks->OS.write(Prefix, strlen(Prefix));
-    Callbacks->SetEmittedTokensOnThisLine();
     // Read and print all of the pragma tokens.
     while (PragmaTok.isNot(tok::eod)) {
       if (PragmaTok.hasLeadingSpace())
@@ -483,7 +486,7 @@ struct UnknownPragmaHandler : public PragmaHandler {
       Callbacks->OS.write(&TokSpell[0], TokSpell.size());
       PP.LexUnexpandedToken(PragmaTok);
     }
-    Callbacks->StartNewLineIfNeeded();
+    Callbacks->setEmittedDirectiveOnThisLine();
   }
 };
 } // end anonymous namespace
@@ -497,6 +500,10 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
   PrevPrevTok.startToken();
   PrevTok.startToken();
   while (1) {
+    if (Callbacks->hasEmittedDirectiveOnThisLine()) {
+      Callbacks->startNewLineIfNeeded();
+      Callbacks->MoveToLine(Tok.getLocation());
+    }
 
     // If this token is at the start of a line, emit newlines if needed.
     if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) {
@@ -533,7 +540,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
       if (Tok.getKind() == tok::comment)
         Callbacks->HandleNewlinesInToken(&S[0], S.size());
     }
-    Callbacks->SetEmittedTokensOnThisLine();
+    Callbacks->setEmittedTokensOnThisLine();
 
     if (Tok.is(tok::eof)) break;
 
index 69d21f8ad68edf544aae89da225b22aa9dffbd7b..4ebe1579d03e4ee5f593677ba790dffda69cf5b1 100644 (file)
@@ -2402,7 +2402,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
   BufferPtr = CurPtr;
 
   // Finally, let the preprocessor handle this.
-  return PP->HandleEndOfFile(Result);
+  return PP->HandleEndOfFile(Result, isPragmaLexer());
 }
 
 /// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from
index d1645adbc252970d29be26dd013a9e250ed42b29..a76e0b2f97e2fcd18e78c73f393747ff9e31a67b 100644 (file)
@@ -9,7 +9,6 @@
 // CHECK: #line
 // CHECK: #pragma warning(push)
 // CHECK:  int foo() { return 0; } }
-// CHECK: #line
 // CHECK: #pragma warning(pop)
 #define A(X) extern "C" { __pragma(warning(push)) \
   int X() { return 0; } \
index 8b68d6ca1f76eac6c83f72d489345daa0e04b8d1..5031ee4edcc6d164e7829250f5d380c7bebe8c02 100644 (file)
@@ -1,4 +1,47 @@
-// RUN: %clang_cc1 %s -E | not grep 'scratch space'
+// RUN: %clang_cc1 %s -fms-extensions -E | FileCheck %s
+// We use -fms-extensions to test both _Pragma and __pragma.
 
-#define push _Pragma ("pack(push)")
-push
+// A long time ago the pragma lexer's buffer showed through in -E output.
+// CHECK-NOT: scratch space
+
+#define push_p _Pragma ("pack(push)")
+push_p
+// CHECK: #pragma pack(push)
+
+push_p _Pragma("pack(push)") __pragma(pack(push))
+// CHECK: #pragma pack(push)
+// CHECK-NEXT: #line 11 "{{.*}}_Pragma-location.c"
+// CHECK-NEXT: #pragma pack(push)
+// CHECK-NEXT: #line 11 "{{.*}}_Pragma-location.c"
+// CHECK-NEXT: #pragma pack(push)
+
+
+#define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS _Pragma("clang diagnostic push") \
+_Pragma("clang diagnostic ignored \"-Wformat-extra-args\"")
+#define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS _Pragma("clang diagnostic pop")
+
+void test () {
+  1;_Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Wformat-extra-args\"")
+  _Pragma("clang diagnostic pop")
+
+  2;__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS
+  3;__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS
+}
+
+// CHECK: void test () {
+// CHECK-NEXT:   1;
+// CHECK-NEXT: #line 24 "{{.*}}_Pragma-location.c"
+// CHECK-NEXT: #pragma clang diagnostic push
+// CHECK-NEXT: #pragma clang diagnostic ignored "-Wformat-extra-args"
+// CHECK-NEXT: #pragma clang diagnostic pop
+
+// CHECK:   2;
+// CHECK-NEXT: #line 28 "{{.*}}_Pragma-location.c"
+// CHECK-NEXT: #pragma clang diagnostic push
+// CHECK-NEXT: #line 28 "{{.*}}_Pragma-location.c"
+// CHECK-NEXT: #pragma clang diagnostic ignored "-Wformat-extra-args"
+// CHECK-NEXT:   3;
+// CHECK-NEXT: #line 29 "{{.*}}_Pragma-location.c"
+// CHECK-NEXT: #pragma clang diagnostic pop
+// CHECK-NEXT: }
index 996c14ca976e754bc7bf9dbf7a1275eea9aad305..1100ea29bba9c32525a1727bb7b34f0a3935539a 100644 (file)
 #endif
 /* baz */
 // CHECK: /* baz */
+
+_Pragma("unknown") // after unknown pragma
+// CHECK: #pragma unknown
+// CHECK-NEXT: #
+// CHECK-NEXT: // after unknown pragma
+
+_Pragma("comment(\"abc\")") // after known pragma
+// CHECK: #pragma comment("abc")
+// CHECK-NEXT: #
+// CHECK-NEXT: // after known pragma