On Friday 16 of March 2012, Lubos Lunak wrote:
> On Friday 16 of March 2012, Chandler Carruth wrote:
> > I've not looked at the patch in detail, but a simple idea: #if 0 block,
> > with a comment explaining why.
>
> That's a very good idea and it seems to work nicely.
>
> I've also added commenting out #pragma once, and now the patch should be
> hopefully fully ready. I've also done a LibreOffice build again and this
> time there wasn't a single problem.
I've still found two minor details, and also made it noticeably faster while
I was at it. But now it's perfect, honest :).
The latest version is attached. This time it is a patch and separately the
new source file (to be put in clang/lib/Rewrite), to make review it easier. I
also do not intend to make further changes until reviewed.
The changes needed elsewhere are:
- adding the new option and invoking the functionality, trivial duplication
of -rewrite-macros
- changes in Lexer class to not access the (null) Preprocessor pointer in raw
mode, which the code normally uses, but temporarily switches to
ParsingPreprocessorDirective mode (apparently a use case that's not been
needed yet)
- addition of MacroExpansionInDirectivesOverride flag to Preprocessor, which
makes it possible to avoid macro expansion everywhere else except in macro
directives, which reduces the time to process files to less than a half (and
to less than with plain -E, making icecream's distributed compilation
actually faster this way). It could be made even faster if the lexer could be
switched to mode where it would parse only comments and preprocessor
directives (nothing else matters in this case), and I expect it would be an
additional boost to distributed compiles, as this step is the bottleneck, but
maybe later ;).
- and a test, which of course passes. Moreover, as already said, I've
successfully compiled LibreOffice using this feature.
--
Lubos Lunak
[email protected]
//===--- RewriteIncludes.cpp - Rewrite includes into their expansions -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This code rewrites include invocations into their expansions. This gives you
// a file with all included files merged into it.
//
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
class RewriteIncludes : public PPCallbacks {
// Information about which #includes were actually performed,
// created by preprocessor callbacks.
struct FileChange {
SourceLocation from;
FileID id;
SrcMgr::CharacteristicKind type;
};
Preprocessor &PP;
SourceManager &SM;
raw_ostream &OS;
bool DisableLineMarkers;
bool UseLineDirective;
std::list< FileChange > FileChanges;
public:
RewriteIncludes(Preprocessor &pp, raw_ostream &os, bool lineMarkers)
: PP(pp), SM(PP.getSourceManager()),
OS(os), DisableLineMarkers(lineMarkers) {
// If we're in microsoft mode, use normal #line instead of line markers.
UseLineDirective = PP.getLangOpts().MicrosoftExt;
}
bool Process( FileID fileId, SrcMgr::CharacteristicKind type );
private:
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID);
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
const FileEntry *File,
SourceLocation EndLoc,
StringRef SearchPath,
StringRef RelativePath);
void WriteLineInfo(const char* filename, int line,
SrcMgr::CharacteristicKind type,
const char *Extra = NULL, unsigned ExtraLen = 0);
void OutputContentsUpTo( unsigned writeEnd, unsigned& nextToWrite,
const llvm::MemoryBuffer* FromFile,
bool EnsureNewline = false );
PresumedLoc CommentOutDirective( Lexer& DirectivesLex,
const Token& StartToken,
unsigned& nextToWrite,
const llvm::MemoryBuffer* FromFile );
const FileChange* FindFileChangeLocation(SourceLocation Loc) const;
StringRef NextIdentifierName(Lexer& RawLex, Token& RawToken);
};
} // end anonymous namespace
void RewriteIncludes::WriteLineInfo(const char* filename, int line,
SrcMgr::CharacteristicKind type,
const char *Extra,
unsigned ExtraLen) {
// Emit #line directives or GNU line markers depending on what mode we're in.
if (UseLineDirective) {
OS << "#line" << ' ' << line << ' ' << '"' << filename;
OS << '"';
} else {
OS << '#' << ' ' << line << ' ' << '"' << filename << '"';
if (ExtraLen)
OS.write(Extra, ExtraLen);
if (type == SrcMgr::C_System)
OS.write(" 3", 2);
else if (type == SrcMgr::C_ExternCSystem)
OS.write(" 3 4", 4);
}
OS << '\n';
}
/// FileChanged - Whenever the preprocessor enters or exits a #include file
/// it invokes this handler.
void RewriteIncludes::FileChanged(SourceLocation Loc,
FileChangeReason Reason,
SrcMgr::CharacteristicKind NewFileType,
FileID) {
if (Reason == EnterFile) {
// InclusionDirective() has already been called, add more info
FileID id = FullSourceLoc(Loc,SM).getFileID();
if (!FileChanges.empty()) { // there may be internal sort-of includes
FileChanges.back().id = id;
FileChanges.back().type = NewFileType;
}
}
}
// This should be called whenever the preprocessor encounters include
// directives. It does not say whether the file has been included, but it
// provides more information about the directive (hash location istead
// of location inside the included file. It is assumed that the matching
// FileChanged() is called after this (if at all).
void RewriteIncludes::InclusionDirective(SourceLocation HashLoc,
const Token&,
StringRef,
bool,
const FileEntry*,
SourceLocation,
StringRef,
StringRef) {
FileChange change;
change.from = HashLoc;
FileChanges.push_back( change );
}
const RewriteIncludes::FileChange*
RewriteIncludes::FindFileChangeLocation(SourceLocation Loc) const {
for (std::list< FileChange >::const_iterator it
= FileChanges.begin(), end = FileChanges.end();
it != end; ++it) {
if (it->from == Loc)
return &*it;
}
return NULL;
}
// Copies next yet written file contents up (and not including writeEnd).
void RewriteIncludes::OutputContentsUpTo(unsigned writeEnd,
unsigned& nextToWrite,
const llvm::MemoryBuffer* FromFile,
bool EnsureNewline ) {
if ( writeEnd > nextToWrite ) {
OS.write( FromFile->getBufferStart() + nextToWrite, writeEnd - nextToWrite );
if (EnsureNewline) {
char LastChar = FromFile->getBufferStart()[ writeEnd - 1 ];
if (LastChar != '\n' && LastChar != '\r')
OS << '\n';
}
nextToWrite = writeEnd;
}
}
PresumedLoc RewriteIncludes::CommentOutDirective( Lexer& DirectiveLex,
const Token& StartToken,
unsigned& nextToWrite,
const llvm::MemoryBuffer* FromFile ) {
OutputContentsUpTo(SM.getFileOffset(StartToken.getLocation()), nextToWrite, FromFile);
Token DirectiveToken;
do {
DirectiveLex.LexFromRawLexer(DirectiveToken);
} while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof));
OS << "#if 0 /* expanded by -rewrite-includes */\n";
OutputContentsUpTo(SM.getFileOffset(DirectiveToken.getLocation())
+ DirectiveToken.getLength(), nextToWrite, FromFile);
OS << "#endif /* expanded by -rewrite-includes */\n";
// return location of EOD (for next line number, otherwise later it might not be exact
// because of whitespace ignoring)
assert(SM.getPresumedLoc(DirectiveToken.getLocation()).isValid());
return SM.getPresumedLoc(DirectiveToken.getLocation());
}
StringRef RewriteIncludes::NextIdentifierName(Lexer& RawLex, Token& RawToken) {
RawLex.LexFromRawLexer(RawToken);
if (RawToken.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawToken);
if (RawToken.is(tok::identifier))
return RawToken.getIdentifierInfo()->getName();
return StringRef();
}
bool RewriteIncludes::Process( FileID fileId,
SrcMgr::CharacteristicKind type )
{
PresumedLoc start = SM.getPresumedLoc(SM.getLocForStartOfFile(fileId));
if( start.isInvalid())
return false;
// Use a raw lexer to analyze the input file, incrementally copying parts of
// it and including contents of included files recursively.
const llvm::MemoryBuffer *FromFile = SM.getBuffer( fileId );
Lexer RawLex(fileId, FromFile, PP.getSourceManager(), PP.getLangOpts());
RawLex.SetCommentRetentionState(false);
WriteLineInfo( start.getFilename(), start.getLine(), type, " 1", 2 );
if (SM.getFileIDSize(fileId) == 0)
return true;
// position in file from which the contents have not yet been copied to the output
unsigned nextToWrite = 0;
Token RawToken;
RawLex.LexFromRawLexer(RawToken);
// It might be beneficial to have a switch that will remove contents of lines
// that are irrevelant for compile, i.e. comments. Comments are actually
// the majority of the resulting file and cleaning up such lines would
// significantly reduce the size of the resulting file without having any
// effect on any following usage (with the exception of human inspection).
while (RawToken.isNot(tok::eof)) {
if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) {
RawLex.setParsingPreprocessorDirective( true );
Token HashToken = RawToken;
RawLex.LexFromRawLexer(RawToken);
if (RawToken.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawToken);
if (RawToken.is(tok::identifier)) {
switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_include_next:
case tok::pp_import: {
// keep the directive in, commented out
// clang sometimes optimizes and does not repeatedly include some
// files even though it should, so all includes need to be commented
PresumedLoc EODPos = CommentOutDirective(RawLex, HashToken,
nextToWrite, FromFile);
// fix up lineinfo, commenting out added lines
bool NeedFixup = true;
if (const FileChange* change = FindFileChangeLocation(
HashToken.getLocation())) {
// now include and recursively process the file
if( Process( change->id, change->type )) {
// and set lineinfo back to this file, if the nested one was actually included
WriteLineInfo( EODPos.getFilename(), EODPos.getLine() + 1,
type, " 2", 2);
NeedFixup = false;
}
}
if( NeedFixup )
WriteLineInfo(EODPos.getFilename(), EODPos.getLine() + 1, type);
break;
}
case tok::pp_pragma: {
StringRef I = NextIdentifierName(RawLex, RawToken);
if (I == "clang" || I == "GCC" ) {
if (NextIdentifierName(RawLex, RawToken) == "system_header") {
// keep the directive in, commented out
PresumedLoc EODPos = CommentOutDirective(RawLex, HashToken,
nextToWrite, FromFile);
// update our own type
type = SM.getFileCharacteristic(RawToken.getLocation());
WriteLineInfo(EODPos.getFilename(), EODPos.getLine() + 1, type);
}
} else if (I == "once") {
// keep the directive in, commented out
PresumedLoc EODPos = CommentOutDirective(RawLex, HashToken,
nextToWrite, FromFile);
WriteLineInfo(EODPos.getFilename(), EODPos.getLine() + 1, type);
}
break;
}
default:
break;
}
}
RawLex.setParsingPreprocessorDirective(false);
RawLex.SetCommentRetentionState(false);
}
RawLex.LexFromRawLexer(RawToken);
}
OutputContentsUpTo(SM.getFileOffset(SM.getLocForEndOfFile(fileId)) + 1,
nextToWrite, FromFile, true);
return true;
}
/// RewriteIncludesInInput - Implement -rewrite-includes mode.
void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
const PreprocessorOutputOptions &Opts) {
SourceManager &SM = PP.getSourceManager();
RewriteIncludes* Rewrite = new RewriteIncludes(PP, *OS, !Opts.ShowLineMarkers);
PP.addPPCallbacks(Rewrite);
// First let the preprocessor process the entire file and call callbacks.
// Callbacks will record which #include's were actually performed.
PP.EnterMainSourceFile();
Token Tok;
// Only preprocessor directives matter here, so disable macro expansion
// everywhere else as an optimization.
// It would be even faster if the preprocessor could be switched to a mode
// where it would parse only preprocessor directives and comments, nothing
// else matters for parsing or processing.
PP.SetMacroExpansionOnlyInDirectives();
do {
PP.Lex(Tok);
} while (Tok.isNot(tok::eof));
Rewrite->Process( SM.getMainFileID(), SrcMgr::C_User );
OS->flush();
}
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index d32ea0b..fc9e230 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -446,6 +446,8 @@ def rewrite_objc : Flag<"-rewrite-objc">,
HelpText<"Rewrite ObjC into C (code rewriter example)">;
def rewrite_macros : Flag<"-rewrite-macros">,
HelpText<"Expand macros without full preprocessing">;
+def rewrite_includes : Flag<"-rewrite-includes">,
+ HelpText<"Expand includes without full preprocessing">;
def migrate : Flag<"-migrate">,
HelpText<"Migrate source code">;
}
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 0ec2f6b..d9b24ba 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -43,6 +43,7 @@ namespace frontend {
PrintPreamble, ///< Print the "preamble" of the input file
PrintPreprocessedInput, ///< -E mode.
RewriteMacros, ///< Expand macros but not #includes.
+ RewriteIncludes, ///< Expand #includes but not macros.
RewriteObjC, ///< ObjC->C Rewriter.
RewriteTest, ///< Rewriter playground
RunAnalysis, ///< Run one or more source code analyses.
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 508c168..6284ccb 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -121,6 +121,13 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// DisableMacroExpansion - True if macro expansion is disabled.
bool DisableMacroExpansion : 1;
+ /// MacroExpansionInDirectivesOverride - Temporarily disables
+ /// DisableMacroExpansion (i.e. enables expansion) when parsing preprocessor
+ /// directives.
+ bool MacroExpansionInDirectivesOverride : 1;
+
+ class ResetMacroExpansionHelper;
+
/// \brief Whether we have already loaded macros from the external source.
mutable bool ReadMacrosFromExternalSource : 1;
@@ -626,6 +633,11 @@ public:
while (Result.getKind() == tok::comment);
}
+ /// Disables macro expansion everywhere except for preprocessor directives.
+ void SetMacroExpansionOnlyInDirectives() {
+ DisableMacroExpansion = true;
+ MacroExpansionInDirectivesOverride = true;
+ }
/// LookAhead - This peeks ahead N tokens and returns that token without
/// consuming any tokens. LookAhead(0) returns the next token that would be
/// returned by Lex(), LookAhead(1) returns the token after it, etc. This
diff --git a/include/clang/Rewrite/FrontendActions.h b/include/clang/Rewrite/FrontendActions.h
index 6e9ecac..ea876d9 100644
--- a/include/clang/Rewrite/FrontendActions.h
+++ b/include/clang/Rewrite/FrontendActions.h
@@ -73,6 +73,11 @@ protected:
void ExecuteAction();
};
+class RewriteIncludesAction : public PreprocessorFrontendAction {
+protected:
+ void ExecuteAction();
+};
+
} // end namespace clang
#endif
diff --git a/include/clang/Rewrite/Rewriters.h b/include/clang/Rewrite/Rewriters.h
index 203b9bc..9704fe3 100644
--- a/include/clang/Rewrite/Rewriters.h
+++ b/include/clang/Rewrite/Rewriters.h
@@ -18,6 +18,7 @@
namespace clang {
class Preprocessor;
+class PreprocessorOutputOptions;
/// RewriteMacrosInInput - Implement -rewrite-macros mode.
void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS);
@@ -25,6 +26,9 @@ void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS);
/// DoRewriteTest - A simple test for the TokenRewriter class.
void DoRewriteTest(Preprocessor &PP, raw_ostream *OS);
+/// RewriteIncludesInInput - Implement -rewrite-includes mode.
+void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts);
+
} // end namespace clang
#endif
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 13a9897..e8dc20e 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -455,6 +455,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::PrintPreamble: return "-print-preamble";
case frontend::PrintPreprocessedInput: return "-E";
case frontend::RewriteMacros: return "-rewrite-macros";
+ case frontend::RewriteIncludes: return "-rewrite-includes";
case frontend::RewriteObjC: return "-rewrite-objc";
case frontend::RewriteTest: return "-rewrite-test";
case frontend::RunAnalysis: return "-analyze";
@@ -1451,6 +1452,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
case OPT_rewrite_macros:
Opts.ProgramAction = frontend::RewriteMacros; break;
+ case OPT_rewrite_includes:
+ Opts.ProgramAction = frontend::RewriteIncludes; break;
case OPT_rewrite_objc:
Opts.ProgramAction = frontend::RewriteObjC; break;
case OPT_rewrite_test:
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 07d2b8d..49d0bb8 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -73,6 +73,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case PrintPreamble: return new PrintPreambleAction();
case PrintPreprocessedInput: return new PrintPreprocessedAction();
case RewriteMacros: return new RewriteMacrosAction();
+ case RewriteIncludes: return new RewriteIncludesAction();
case RewriteObjC: return new RewriteObjCAction();
case RewriteTest: return new RewriteTestAction();
case RunAnalysis: return new ento::AnalysisAction();
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index a49ab04..65d96d8 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -2020,7 +2020,7 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
// directly.
FormTokenWithChars(Result, CurPtr, tok::comment);
- if (!ParsingPreprocessorDirective)
+ if (!ParsingPreprocessorDirective || LexingRawMode)
return true;
// If this BCPL-style comment is in a macro definition, transmogrify it into
@@ -2622,7 +2622,8 @@ LexNextToken:
ParsingPreprocessorDirective = false;
// Restore comment saving mode, in case it was disabled for directive.
- SetCommentRetentionState(PP->getCommentRetentionState());
+ if (!LexingRawMode)
+ SetCommentRetentionState(PP->getCommentRetentionState());
// Since we consumed a newline, we are back at the start of a line.
IsAtStartOfLine = true;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 53bb5c3..d69dad5 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -553,6 +553,22 @@ const FileEntry *Preprocessor::LookupFile(
// Preprocessor Directive Handling.
//===----------------------------------------------------------------------===//
+class Preprocessor::ResetMacroExpansionHelper
+{
+public:
+ ResetMacroExpansionHelper(Preprocessor*pp)
+ : PP(pp), save(pp->DisableMacroExpansion) {
+ if (pp->MacroExpansionInDirectivesOverride)
+ pp->DisableMacroExpansion = false;
+ }
+ ~ResetMacroExpansionHelper() {
+ PP->DisableMacroExpansion = save;
+ }
+private:
+ Preprocessor* PP;
+ bool save;
+};
+
/// HandleDirective - This callback is invoked when the lexer sees a # token
/// at the start of a line. This consumes the directive, modifies the
/// lexer/preprocessor state, and advances the lexer(s) so that the next token
@@ -604,6 +620,10 @@ void Preprocessor::HandleDirective(Token &Result) {
Diag(Result, diag::ext_embedded_directive);
}
+ // temporarily enable macro expansion if set so
+ // and reset to previous state when returning from this function
+ ResetMacroExpansionHelper helper(this);
+
TryAgain:
switch (Result.getKind()) {
case tok::eod:
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 6142436..4c98f76 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -133,6 +133,7 @@ void Preprocessor::Initialize(const TargetInfo &Target) {
// Macro expansion is enabled.
DisableMacroExpansion = false;
+ MacroExpansionInDirectivesOverride = false;
InMacroArgs = false;
NumCachedTokenLexers = 0;
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
index 2a05040..8070ba2 100644
--- a/lib/Rewrite/CMakeLists.txt
+++ b/lib/Rewrite/CMakeLists.txt
@@ -6,6 +6,7 @@ add_clang_library(clangRewrite
FrontendActions.cpp
HTMLPrint.cpp
HTMLRewrite.cpp
+ RewriteIncludes.cpp
RewriteMacros.cpp
RewriteModernObjC.cpp
RewriteObjC.cpp
diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp
index 1753325..e462671 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/lib/Rewrite/FrontendActions.cpp
@@ -181,3 +181,11 @@ void RewriteTestAction::ExecuteAction() {
DoRewriteTest(CI.getPreprocessor(), OS);
}
+
+void RewriteIncludesAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OS) return;
+
+ RewriteIncludesInInput(CI.getPreprocessor(), OS, CI.getPreprocessorOutputOpts());
+}
diff --git a/test/Frontend/rewrite-includes.c b/test/Frontend/rewrite-includes.c
new file mode 100644
index 0000000..a165d32
--- /dev/null
+++ b/test/Frontend/rewrite-includes.c
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -verify -rewrite-includes -DFIRST %s -o %t
+// RUN: cat %t | FileCheck -strict-whitespace %s
+// STARTCOMPARE
+#define A(a,b) a ## b
+A(1,2)
+#include "rewrite-includes1.h"
+#ifdef FIRST
+#define HEADER "rewrite-includes3.h"
+#include HEADER
+#else
+#include "rewrite-includes4.h"
+#endif
+#/**/include /**/ "rewrite-includes5.h" /**/ \
+
+#include "rewrite-includes6.h" // comment
+
+#include "rewrite-includes6.h" /* comment
+ continues */
+// ENDCOMPARE
+
+// CHECK: {{^}}// STARTCOMPARE{{$}}
+// CHECK-NEXT: {{^}}#define A(a,b) a ## b{{$}}
+// CHECK-NEXT: {{^}}A(1,2){{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes1.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes1.h" 1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#pragma clang system_header{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes1.h" 3{{$}}
+// CHECK-NEXT: {{^}}included_line1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes2.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes2.h" 1 3{{$}}
+// CHECK-NEXT: {{^}}included_line2{{$}}
+// CHECK-NEXT: {{^}}# 3 "{{.*}}rewrite-includes1.h" 2 3{{$}}
+// CHECK-NEXT: {{^}}# 7 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#ifdef FIRST{{$}}
+// CHECK-NEXT: {{^}}#define HEADER "rewrite-includes3.h"{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include HEADER{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes3.h" 1{{$}}
+// CHECK-NEXT: {{^}}included_line3{{$}}
+// CHECK-NEXT: {{^}}# 10 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#else{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes4.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 12 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#/**/include /**/ "rewrite-includes5.h" /**/ {{\\}}{{$}}
+// CHECK-NEXT: {{^}} {{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes5.h" 1{{$}}
+// CHECK-NEXT: {{^}}included_line5{{$}}
+// CHECK-NEXT: {{^}}# 15 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes6.h" // comment{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes6.h" 1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#pragma once{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 2 "{{.*}}rewrite-includes6.h"{{$}}
+// CHECK-NEXT: {{^}}included_line6{{$}}
+// CHECK-NEXT: {{^}}# 16 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}} {{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes6.h" /* comment{{$}}
+// CHECK-NEXT: {{^}} continues */{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 19 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}// ENDCOMPARE{{$}}
diff --git a/test/Frontend/rewrite-includes1.h b/test/Frontend/rewrite-includes1.h
new file mode 100644
index 0000000..1b6c80d
--- /dev/null
+++ b/test/Frontend/rewrite-includes1.h
@@ -0,0 +1,3 @@
+#pragma clang system_header
+included_line1
+#include "rewrite-includes2.h"
diff --git a/test/Frontend/rewrite-includes2.h b/test/Frontend/rewrite-includes2.h
new file mode 100644
index 0000000..1114e51
--- /dev/null
+++ b/test/Frontend/rewrite-includes2.h
@@ -0,0 +1 @@
+included_line2
diff --git a/test/Frontend/rewrite-includes3.h b/test/Frontend/rewrite-includes3.h
new file mode 100644
index 0000000..3757bc8
--- /dev/null
+++ b/test/Frontend/rewrite-includes3.h
@@ -0,0 +1 @@
+included_line3
diff --git a/test/Frontend/rewrite-includes4.h b/test/Frontend/rewrite-includes4.h
new file mode 100644
index 0000000..b4e25d2
--- /dev/null
+++ b/test/Frontend/rewrite-includes4.h
@@ -0,0 +1 @@
+included_line4
diff --git a/test/Frontend/rewrite-includes5.h b/test/Frontend/rewrite-includes5.h
new file mode 100644
index 0000000..934bf41
--- /dev/null
+++ b/test/Frontend/rewrite-includes5.h
@@ -0,0 +1 @@
+included_line5
diff --git a/test/Frontend/rewrite-includes6.h b/test/Frontend/rewrite-includes6.h
new file mode 100644
index 0000000..c18e501
--- /dev/null
+++ b/test/Frontend/rewrite-includes6.h
@@ -0,0 +1,2 @@
+#pragma once
+included_line6
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits