- Update to r167719 from release_32 branch

* Thread local variables may have a specified TLS model.
  * LLVM now has a loop optimizer.
  * SROA has been rewritten to be more powerful.
  * A new optimization pass added to merge stack objects
    which are used in disjoint areas of the code.
  * LLVM now merge consecutive loads and stores.
  * New TableGen infrastructure to support bundling for
    Very Long Instruction Word (VLIW) architectures.
  * Added a new target independent VLIW packetizer.
  * A probability based block placement and code layout algorithm
    was added to LLVM's code generator.
  * The ARM target now includes a full featured macro assembler,
    including direct-to-object module support for clang.
  * A new IR-level pass, called "TargetTransformInfo" provides
    a number of low-level interfaces.
- Drop following patches (fixed upstream)
  * arm-suse-support.patch
  * pr12463.patch
  * pr13141.patch
  * pr13303.patch
  * rewrite-includes.patch

OBS-URL: https://build.opensuse.org/package/show/devel:tools:compiler/llvm?expand=0&rev=166
This commit is contained in:
Ismail Dönmez 2012-11-12 10:06:01 +00:00 committed by Git OBS Bridge
parent b6f01f8dd7
commit 3f638bdf7c
9 changed files with 39 additions and 1112 deletions

View File

@ -1,74 +0,0 @@
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp.orig
+++ tools/clang/lib/Driver/Tools.cpp
@@ -611,6 +611,11 @@ static StringRef getARMFloatABI(const Dr
}
case llvm::Triple::Linux: {
+ StringRef ArchName = getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
+ if (Triple.getEnvironment() == llvm::Triple::GNUEABIHF || ArchName.startswith("v7")) {
+ FloatABI = "hard";
+ break;
+ } else
if (Triple.getEnvironment() == llvm::Triple::GNUEABI) {
FloatABI = "softfp";
break;
@@ -623,6 +627,9 @@ static StringRef getARMFloatABI(const Dr
case llvm::Triple::GNUEABI:
FloatABI = "softfp";
break;
+ case llvm::Triple::GNUEABIHF:
+ FloatABI = "hard";
+ break;
case llvm::Triple::EABI:
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
FloatABI = "softfp";
@@ -665,6 +672,7 @@ void Clang::AddARMTargetArgs(const ArgLi
// Select the default based on the platform.
switch(Triple.getEnvironment()) {
case llvm::Triple::ANDROIDEABI:
+ case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABI:
ABIName = "aapcs-linux";
break;
@@ -730,10 +738,11 @@ void Clang::AddARMTargetArgs(const ArgLi
// Setting -msoft-float effectively disables NEON because of the GCC
// implementation, although the same isn't true of VFP or VFP3.
- if (FloatABI == "soft") {
+// if (FloatABI == "soft") {
+// we do not use neon on suse so far, disabling it always to avoid incompatible ABI
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-neon");
- }
+// }
// Kernel code has more strict alignment requirements.
if (KernelOrKext) {
@@ -5062,8 +5071,9 @@ void linuxtools::Assemble::ConstructJob(
CmdArgs.push_back("-many");
} else if (getToolChain().getArch() == llvm::Triple::arm) {
StringRef MArch = getToolChain().getArchName();
- if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
- CmdArgs.push_back("-mfpu=neon");
+// we do not use neon on suse so far, disabling it always to avoid incompatible ABI
+// if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
+// CmdArgs.push_back("-mfpu=neon");
} else if (getToolChain().getArch() == llvm::Triple::mips ||
getToolChain().getArch() == llvm::Triple::mipsel ||
getToolChain().getArch() == llvm::Triple::mips64 ||
Index: tools/clang/lib/Driver/ToolChains.cpp
===================================================================
--- tools/clang/lib/Driver/ToolChains.cpp.orig
+++ tools/clang/lib/Driver/ToolChains.cpp
@@ -1185,6 +1185,9 @@ Generic_GCC::GCCInstallationDetector::GC
static const char *const ARMLibDirs[] = { "/lib" };
static const char *const ARMTriples[] = {
"arm-linux-gnueabi",
+ "armv5el-suse-linux-gnueabi",
+ "armv7hl-suse-linux-gnueabi",
+ "armv7hl-suse-linux-gnueabihf",
"arm-linux-androideabi"
};

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1287cecc9644629b4f73251b03a0cff047fdcaea39b461650eb5117767478b85
size 16555076

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f2ec6ac271a0ea1f99eb171f43ae9eeb8607fd10c329592d66dfc15300c572e0
size 16451676

View File

@ -1,3 +1,30 @@
-------------------------------------------------------------------
Mon Nov 12 08:05:08 UTC 2012 - idonmez@suse.com
- Update to r167719 from release_32 branch
* Thread local variables may have a specified TLS model.
* LLVM now has a loop optimizer.
* SROA has been rewritten to be more powerful.
* A new optimization pass added to merge stack objects
which are used in disjoint areas of the code.
* LLVM now merge consecutive loads and stores.
* New TableGen infrastructure to support bundling for
Very Long Instruction Word (VLIW) architectures.
* Added a new target independent VLIW packetizer.
* A probability based block placement and code layout algorithm
was added to LLVM's code generator.
* The ARM target now includes a full featured macro assembler,
including direct-to-object module support for clang.
* A new IR-level pass, called "TargetTransformInfo" provides
a number of low-level interfaces.
- Drop following patches (fixed upstream)
* arm-suse-support.patch
* pr12463.patch
* pr13141.patch
* pr13303.patch
* rewrite-includes.patch
-------------------------------------------------------------------
Sat Oct 27 06:01:06 UTC 2012 - coolo@suse.com

View File

@ -16,12 +16,12 @@
#
%define _revision 157047
%define _revision 167719
%define _release_version 3.1
%define _supported_archs "arm,x86"
Name: llvm
Version: 3.1
Version: 3.1.99.r167719
Release: 0
Summary: Low Level Virtual Machine
License: NCSA
@ -38,11 +38,6 @@ Patch3: clang-disable-ada-extension.patch
# PATCH-FIX-OPENSUSE default-to-i586.patch -- Use i586 as default target for 32bit
Patch4: default-to-i586.patch
Patch5: clang-fix-mips-test.patch
Patch6: rewrite-includes.patch
Patch7: pr12463.patch
Patch8: pr13141.patch
Patch9: pr13303.patch
Patch10: arm-suse-support.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: autoconf
BuildRequires: automake
@ -135,15 +130,6 @@ This package contains vim plugins for LLVM like syntax highlighting.
%ifarch x86_64
%patch5 -p1
%endif
%patch6 -p0
# sle11 patch cannot create empty files
touch tools/clang/test/Frontend/Inputs/rewrite-includes9.h
%patch7 -p0
%patch8 -p0
%patch9 -p1
%ifarch %arm
%patch10
%endif
# We hardcode i586
rm tools/clang/test/Driver/x86_features.c
@ -178,11 +164,17 @@ pushd stage1
%endif
--enable-targets=host
make %{?_smp_mflags}
# compiler-rt doesn't like gcc
mv ../projects/compiler-rt ..
make %{?_smp_mflags} clang-only
popd
pushd stage2
# Get back compiler-rt
mv ../compiler-rt ../projects/compiler-rt
# autotools ignore --libdir
mkdir Release+Debug
ln -s lib Release+Debug/lib64

View File

@ -1,111 +0,0 @@
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index fea0fe1..1046972 100644
--- tools/clang/lib/Sema/SemaExpr.cpp
+++ tools/clang/lib/Sema/SemaExpr.cpp
@@ -6577,23 +6577,29 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
checkEnumComparison(*this, Loc, LHS, RHS);
if (!LHSType->hasFloatingRepresentation() &&
- !(LHSType->isBlockPointerType() && IsRelational) &&
- !LHS.get()->getLocStart().isMacroID() &&
- !RHS.get()->getLocStart().isMacroID()) {
+ !(LHSType->isBlockPointerType() && IsRelational)) {
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
//
- // NOTE: Don't warn about comparison expressions resulting from macro
- // expansion. Also don't warn about comparisons which are only self
+ // NOTE: Don't warn about self-comparison expressions resulting from macro
+ // expansion, unless they don't make sense at all.
+ // Also don't warn about comparisons which are only self
// comparisons within a template specialization. The warnings should catch
// obvious cases in the definition of the template anyways. The idea is to
// warn when the typed comparison operator will always evaluate to the same
// result.
+ bool InMacro = LHS.get()->getLocStart().isMacroID() ||
+ RHS.get()->getLocStart().isMacroID();
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped)) {
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) {
+ if (isa<CastExpr>(LHSStripped))
+ LHSStripped = LHSStripped->IgnoreParenCasts();
if (DRL->getDecl() == DRR->getDecl() &&
- !IsWithinTemplateSpecialization(DRL->getDecl())) {
+ !IsWithinTemplateSpecialization(DRL->getDecl()) &&
+ !InMacro &&
+ !isa<StringLiteral>(LHSStripped) &&
+ !isa<ObjCEncodeExpr>(LHSStripped)) {
DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
<< 0 // self-
<< (Opc == BO_EQ
@@ -6602,23 +6608,26 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
} else if (LHSType->isArrayType() && RHSType->isArrayType() &&
!DRL->getDecl()->getType()->isReferenceType() &&
!DRR->getDecl()->getType()->isReferenceType()) {
- // what is it always going to eval to?
- char always_evals_to;
switch(Opc) {
case BO_EQ: // e.g. array1 == array2
- always_evals_to = 0; // false
+ if (!InMacro)
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
+ << 1 // array
+ << 0 /* evaluates to false */ );
break;
case BO_NE: // e.g. array1 != array2
- always_evals_to = 1; // true
+ if (!InMacro)
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
+ << 1 // array
+ << 1 /* evaluates to true */ );
break;
- default:
+ default: // e.g. array1 <= array2
// best we can say is 'a constant'
- always_evals_to = 2; // e.g. array1 <= array2
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
+ << 1 // array
+ << 2 /* evaluates to constant */ );
break;
}
- DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
- << 1 // array
- << always_evals_to);
}
}
}
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index 72cff65..b17b6ec 100644
--- tools/clang/test/Sema/exprs.c
+++ tools/clang/test/Sema/exprs.c
@@ -125,6 +125,12 @@ int test12b(const char *X) {
return sizeof(X == "foo"); // no-warning
}
+// PR12463
+#define FOO_LITERAL "foo"
+int test12c(const char *X) {
+ return X == FOO_LITERAL; // expected-warning {{comparison against a string literal is unspecified (use strncmp instead)}}
+}
+
// rdar://6719156
void test13(
void (^P)()) { // expected-error {{blocks support disabled - compile with -fblocks}}
diff --git a/test/Sema/self-comparison.c b/test/Sema/self-comparison.c
index edb3a6a..8679a3f 100644
--- tools/clang/test/Sema/self-comparison.c
+++ tools/clang/test/Sema/self-comparison.c
@@ -72,6 +72,13 @@ int array_comparisons() {
return array1 <= array2; // expected-warning{{array comparison always evaluates to a constant}}
return array1 > array2; // expected-warning{{array comparison always evaluates to a constant}}
return array1 >= array2; // expected-warning{{array comparison always evaluates to a constant}}
+ // Issue a warning for this even if macro expansion is involved (PR12463)
+#define ARRAY1 array1
+#define ARRAY2 array2
+ return ARRAY1 < ARRAY2; // expected-warning{{array comparison always evaluates to a constant}}
+ return ARRAY1 <= ARRAY2; // expected-warning{{array comparison always evaluates to a constant}}
+ return ARRAY1 > ARRAY2; // expected-warning{{array comparison always evaluates to a constant}}
+ return ARRAY1 >= ARRAY2; // expected-warning{{array comparison always evaluates to a constant}}
}

View File

@ -1,28 +0,0 @@
From e9ddb0fd37e4245392af7e8f1e2c86a44d4339ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= <l.lunak@suse.cz>
Date: Mon, 18 Jun 2012 22:23:37 +0200
Subject: [PATCH] do not reject PCH because of -DFOO -DFOO duplication
---
lib/Serialization/ASTReader.cpp | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index f224056..d176ee3 100644
--- tools/clang/lib/Serialization/ASTReader.cpp
+++ tools/clang/lib/Serialization/ASTReader.cpp
@@ -259,6 +259,11 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
// definitions and they may appear at any point in the output.
std::sort(CmdLineLines.begin(), CmdLineLines.end());
std::sort(PCHLines.begin(), PCHLines.end());
+ // And remove duplicated definitions.
+ CmdLineLines.resize(
+ std::unique(CmdLineLines.begin(), CmdLineLines.end())-CmdLineLines.begin());
+ PCHLines.resize(
+ std::unique(PCHLines.begin(), PCHLines.end())-PCHLines.begin());
// Determine which predefines that were used to build the PCH file are missing
// from the command line.
--
1.7.7

View File

@ -1,58 +0,0 @@
commit 5cf55e1c6a22ae066db5066fdc69f99564ace8ea
Author: Eric Christopher <echristo@apple.com>
Date: Thu Jul 12 23:30:25 2012 +0000
The end of the prologue should be marked with is_stmt.
Fixes PR13303.
Patch by Paul Robinson!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160148 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 038792b..649684a 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -1382,7 +1382,7 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) {
MF->getFunction()->getContext());
recordSourceLine(FnStartDL.getLine(), FnStartDL.getCol(),
FnStartDL.getScope(MF->getFunction()->getContext()),
- 0);
+ DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0);
}
}
diff --git a/test/DebugInfo/X86/pr13303.ll b/test/DebugInfo/X86/pr13303.ll
new file mode 100644
index 0000000..e820cb5
--- /dev/null
+++ b/test/DebugInfo/X86/pr13303.ll
@@ -0,0 +1,28 @@
+; RUN: llc %s -o %t -filetype=obj -mtriple=x86_64-unknown-linux-gnu
+; RUN: llvm-dwarfdump %t | FileCheck %s
+; PR13303
+
+; Check that the prologue ends with is_stmt here.
+; CHECK: 0x0000000000000000 {{.*}} is_stmt
+
+define i32 @main() nounwind uwtable {
+entry:
+ %retval = alloca i32, align 4
+ store i32 0, i32* %retval
+ ret i32 0, !dbg !10
+}
+
+!llvm.dbg.cu = !{!0}
+
+!0 = metadata !{i32 786449, i32 0, i32 12, metadata !"PR13303.c", metadata !"/home/probinson", metadata !"clang version 3.2 (trunk 160143)", i1 true, i1 false, metadata !"", i32 0, metadata !1, metadata !1, metadata !3, metadata !1} ; [ DW_TAG_compile_unit ] [/home/probinson/PR13303.c] [DW_LANG_C99]
+!1 = metadata !{metadata !2}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{metadata !5}
+!5 = metadata !{i32 786478, i32 0, metadata !6, metadata !"main", metadata !"main", metadata !"", metadata !6, i32 1, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 0, i1 false, i32 ()* @main, null, null, metadata !1, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [main]
+!6 = metadata !{i32 786473, metadata !"PR13303.c", metadata !"/home/probinson", null} ; [ DW_TAG_file_type ]
+!7 = metadata !{i32 786453, i32 0, metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!8 = metadata !{metadata !9}
+!9 = metadata !{i32 786468, null, metadata !"int", null, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!10 = metadata !{i32 1, i32 14, metadata !11, null}
+!11 = metadata !{i32 786443, metadata !5, i32 1, i32 12, metadata !6, i32 0} ; [ DW_TAG_lexical_block ] [/home/probinson/PR13303.c]

View File

@ -1,821 +0,0 @@
diff --git tools/clang/include/clang/Driver/CC1Options.td tools/clang/include/clang/Driver/CC1Options.td
index 83c988a..b7deed0 100644
--- tools/clang/include/clang/Driver/CC1Options.td
+++ tools/clang/include/clang/Driver/CC1Options.td
@@ -814,6 +814,8 @@ def dM : Flag<"-dM">,
HelpText<"Print macro definitions in -E mode instead of normal output">;
def dD : Flag<"-dD">,
HelpText<"Print macro definitions in -E mode in addition to normal output">;
+def frewrite_includes : Flag<"-frewrite-includes">,
+ HelpText<"Expand includes without full preprocessing">;
//===----------------------------------------------------------------------===//
// OpenCL Options
diff --git tools/clang/include/clang/Driver/Options.td tools/clang/include/clang/Driver/Options.td
index b796771..f58d824 100644
--- tools/clang/include/clang/Driver/Options.td
+++ tools/clang/include/clang/Driver/Options.td
@@ -362,6 +362,9 @@ def fno_trapping_math : Flag<"-fno-trapping-math">, Group<f_Group>;
def ffor_scope : Flag<"-ffor-scope">, Group<f_Group>;
def fno_for_scope : Flag<"-fno-for-scope">, Group<f_Group>;
+def frewrite_includes : Flag<"-frewrite-includes">, Group<f_Group>;
+def fno_rewrite_includes : Flag<"-fno-rewrite-includes">, Group<f_Group>;
+
def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>;
def fgnu89_inline : Flag<"-fgnu89-inline">, Group<f_Group>;
diff --git tools/clang/include/clang/Frontend/FrontendOptions.h tools/clang/include/clang/Frontend/FrontendOptions.h
index 888388c..48cd317 100644
--- tools/clang/include/clang/Frontend/FrontendOptions.h
+++ tools/clang/include/clang/Frontend/FrontendOptions.h
@@ -42,7 +42,7 @@ namespace frontend {
PrintDeclContext, ///< Print DeclContext and their Decls.
PrintPreamble, ///< Print the "preamble" of the input file
PrintPreprocessedInput, ///< -E mode.
- RewriteMacros, ///< Expand macros but not #includes.
+ RewriteMacros, ///< Expand macros but not \#includes.
RewriteObjC, ///< ObjC->C Rewriter.
RewriteTest, ///< Rewriter playground
RunAnalysis, ///< Run one or more source code analyses.
diff --git tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h
index 1eda0d4..31724cd 100644
--- tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h
+++ tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -21,6 +21,7 @@ public:
unsigned ShowLineMarkers : 1; ///< Show #line markers.
unsigned ShowMacroComments : 1; ///< Show comments, even in macros.
unsigned ShowMacros : 1; ///< Print macro definitions.
+ unsigned RewriteIncludes : 1; ///< Preprocess include directives only.
public:
PreprocessorOutputOptions() {
@@ -29,6 +30,7 @@ public:
ShowLineMarkers = 1;
ShowMacroComments = 0;
ShowMacros = 0;
+ RewriteIncludes = 0;
}
};
diff --git tools/clang/include/clang/Lex/Preprocessor.h tools/clang/include/clang/Lex/Preprocessor.h
index 055008f..638b4aa 100644
--- tools/clang/include/clang/Lex/Preprocessor.h
+++ tools/clang/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;
@@ -634,6 +641,12 @@ 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 tools/clang/include/clang/Rewrite/FrontendActions.h tools/clang/include/clang/Rewrite/FrontendActions.h
index 6e9ecac..ea876d9 100644
--- tools/clang/include/clang/Rewrite/FrontendActions.h
+++ tools/clang/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 tools/clang/include/clang/Rewrite/Rewriters.h tools/clang/include/clang/Rewrite/Rewriters.h
index 203b9bc..f5ade5a 100644
--- tools/clang/include/clang/Rewrite/Rewriters.h
+++ tools/clang/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,10 @@ void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS);
/// DoRewriteTest - A simple test for the TokenRewriter class.
void DoRewriteTest(Preprocessor &PP, raw_ostream *OS);
+/// RewriteIncludesInInput - Implement -frewrite-includes mode.
+void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
+ const PreprocessorOutputOptions &Opts);
+
} // end namespace clang
#endif
diff --git tools/clang/lib/Driver/Tools.cpp tools/clang/lib/Driver/Tools.cpp
index 47b5294..c0504e7 100644
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -2106,6 +2106,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.getLastArg(options::OPT_fapple_kext))
CmdArgs.push_back("-fapple-kext");
+ if (Args.hasFlag(options::OPT_frewrite_includes,
+ options::OPT_fno_rewrite_includes, false))
+ CmdArgs.push_back("-frewrite-includes");
+
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
diff --git tools/clang/lib/Frontend/CompilerInvocation.cpp tools/clang/lib/Frontend/CompilerInvocation.cpp
index 4c5b063..28935ce 100644
--- tools/clang/lib/Frontend/CompilerInvocation.cpp
+++ tools/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2058,6 +2058,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
Opts.ShowMacroComments = Args.hasArg(OPT_CC);
Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
+ Opts.RewriteIncludes = Args.hasArg(OPT_frewrite_includes);
}
static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
diff --git tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 07d2b8d..0824978 100644
--- tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -71,7 +71,12 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case PrintDeclContext: return new DeclContextPrintAction();
case PrintPreamble: return new PrintPreambleAction();
- case PrintPreprocessedInput: return new PrintPreprocessedAction();
+ case PrintPreprocessedInput: {
+ if (CI.getPreprocessorOutputOpts().RewriteIncludes)
+ return new RewriteIncludesAction();
+ return new PrintPreprocessedAction();
+ }
+
case RewriteMacros: return new RewriteMacrosAction();
case RewriteObjC: return new RewriteObjCAction();
case RewriteTest: return new RewriteTestAction();
diff --git tools/clang/lib/Lex/Lexer.cpp tools/clang/lib/Lex/Lexer.cpp
index 535a852..aa424b4 100644
--- tools/clang/lib/Lex/Lexer.cpp
+++ tools/clang/lib/Lex/Lexer.cpp
@@ -2022,7 +2022,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
@@ -2625,7 +2625,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 tools/clang/lib/Lex/PPDirectives.cpp tools/clang/lib/Lex/PPDirectives.cpp
index 625a204..29a8614 100644
--- tools/clang/lib/Lex/PPDirectives.cpp
+++ tools/clang/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 tools/clang/lib/Lex/Preprocessor.cpp tools/clang/lib/Lex/Preprocessor.cpp
index 06e5685..f5d7a51 100644
--- tools/clang/lib/Lex/Preprocessor.cpp
+++ tools/clang/lib/Lex/Preprocessor.cpp
@@ -134,6 +134,7 @@ void Preprocessor::Initialize(const TargetInfo &Target) {
// Macro expansion is enabled.
DisableMacroExpansion = false;
+ MacroExpansionInDirectivesOverride = false;
InMacroArgs = false;
InMacroArgPreExpansion = false;
NumCachedTokenLexers = 0;
diff --git tools/clang/lib/Rewrite/CMakeLists.txt tools/clang/lib/Rewrite/CMakeLists.txt
index 2a05040..8070ba2 100644
--- tools/clang/lib/Rewrite/CMakeLists.txt
+++ tools/clang/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 tools/clang/lib/Rewrite/FrontendActions.cpp tools/clang/lib/Rewrite/FrontendActions.cpp
index 1753325..e462671 100644
--- tools/clang/lib/Rewrite/FrontendActions.cpp
+++ tools/clang/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 tools/clang/lib/Rewrite/RewriteIncludes.cpp tools/clang/lib/Rewrite/RewriteIncludes.cpp
new file mode 100644
index 0000000..b7de20c
--- /dev/null
+++ tools/clang/lib/Rewrite/RewriteIncludes.cpp
@@ -0,0 +1,362 @@
+//===--- 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;
+using namespace llvm;
+
+namespace {
+
+/// Class representing the whole rewriting process and global data for it.
+class IncludeRewriter : 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;
+ typedef std::map<unsigned, FileChange> FileChangeMap;
+ FileChangeMap FileChanges;
+ unsigned LastInsertedFileChange;
+ class File;
+public:
+ IncludeRewriter(Preprocessor &PP, raw_ostream &OS,
+ const PreprocessorOutputOptions &Opts);
+ void Process();
+ 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);
+private:
+ const FileChange* FindFileChangeLocation(SourceLocation Loc) const;
+};
+
+/// Class representing the process of rewriting one source file.
+class IncludeRewriter::File {
+ IncludeRewriter* Rewriter;
+ Preprocessor &PP;
+ SourceManager &SM;
+ raw_ostream &OS;
+ FileID FileId;
+ SrcMgr::CharacteristicKind Type;
+ const MemoryBuffer *FromFile;
+ const char* FileName;
+ SourceLocation StartLocation;
+ bool Invalid;
+ const char* EOL;
+ OwningPtr<Lexer> RawLex;
+ // file position from which the content has not yet been copied to the output
+ unsigned NextToWrite;
+ int Line; // current input file line number
+public:
+ File(IncludeRewriter* Rewriter, FileID FileId,
+ SrcMgr::CharacteristicKind Type);
+ bool Process();
+private:
+ void WriteLineInfo(StringRef Extra = StringRef());
+ void OutputContentUpTo(unsigned WriteEnd, bool EnsureNewline = false);
+ void CommentOutDirective(const Token& StartToken);
+ StringRef NextIdentifierName(Token& RawToken);
+ void DetectEOL();
+ unsigned CountNewLines(const char* Pos, int Len);
+};
+
+} // end anonymous namespace
+
+IncludeRewriter::IncludeRewriter(Preprocessor &pp, raw_ostream &os,
+ const PreprocessorOutputOptions &Opts)
+ : PP(pp), SM(PP.getSourceManager()), OS(os),
+ DisableLineMarkers(!Opts.ShowLineMarkers), LastInsertedFileChange(0) {
+ // If we're in microsoft mode, use normal #line instead of line markers.
+ UseLineDirective = PP.getLangOpts().MicrosoftExt;
+}
+
+/// FileChanged - Whenever the preprocessor enters or exits a #include file
+/// it invokes this handler.
+void IncludeRewriter::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 (LastInsertedFileChange != 0) { // there may be e.g. "<built-in>" first
+ FileChange& Ref = FileChanges[LastInsertedFileChange];
+ Ref.Id = Id;
+ Ref.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 IncludeRewriter::InclusionDirective(SourceLocation HashLoc,
+ const Token &/*IncludeTok*/,
+ StringRef /*FileName*/,
+ bool /*IsAngled*/,
+ const FileEntry* /*File*/,
+ SourceLocation /*EndLoc*/,
+ StringRef /*SearchPath*/,
+ StringRef /*RelativePath*/) {
+ FileChange Change;
+ Change.From = HashLoc;
+ LastInsertedFileChange = HashLoc.getRawEncoding();
+ FileChanges[LastInsertedFileChange] = Change;
+}
+
+const IncludeRewriter::FileChange*
+IncludeRewriter::FindFileChangeLocation(SourceLocation Loc) const {
+ FileChangeMap ::const_iterator Find = FileChanges.find(Loc.getRawEncoding());
+ if(Find != FileChanges.end())
+ return &Find->second;
+ return NULL;
+}
+
+void IncludeRewriter::Process() {
+ File MainFile(this, SM.getMainFileID(), SrcMgr::C_User);
+ MainFile.Process();
+}
+
+
+IncludeRewriter::File::File(IncludeRewriter* Rewriter,
+ FileID FileId,
+ SrcMgr::CharacteristicKind Type)
+ : Rewriter(Rewriter)
+ , PP(Rewriter->PP)
+ , SM(Rewriter->SM)
+ , OS(Rewriter->OS)
+ , FileId(FileId)
+ , Type(Type)
+ , Invalid(true)
+ , NextToWrite(0)
+ , Line(1) {
+
+ StartLocation = SM.getLocForStartOfFile(FileId);
+ FileName = SM.getBufferName(StartLocation, &Invalid);
+ if (Invalid)
+ return;
+
+ // Use a raw lexer to analyze the input file, incrementally copying parts of
+ // it and including content of included files recursively.
+ FromFile = SM.getBuffer(FileId);
+ RawLex.reset( new Lexer(FileId, FromFile, PP.getSourceManager(), PP.getLangOpts()));
+ RawLex->SetCommentRetentionState(false);
+ DetectEOL();
+
+ WriteLineInfo(" 1");
+}
+
+bool IncludeRewriter::File::Process()
+{
+ if (Invalid)
+ return false;
+ if (SM.getFileIDSize(FileId) == 0)
+ return true;
+
+ Token RawToken;
+ RawLex->LexFromRawLexer(RawToken);
+
+ // TODO: It might be beneficial to have a switch that removes content of lines
+ // that are irrevelant for compile, i.e. comments. Comments are usually
+ // a significant part 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, otherwise valid directives would be left in)
+ CommentOutDirective(HashToken);
+ // fix up lineinfo, commenting out has added lines
+ bool NeedFixup = true;
+ if (const FileChange* Change = Rewriter->FindFileChangeLocation(
+ HashToken.getLocation())) {
+ // now include and recursively process the file
+ File IncludedFile(Rewriter, Change->Id, Change->Type);
+ if (IncludedFile.Process()) {
+ // and set lineinfo back to this file, if the nested one was
+ // actually included
+ WriteLineInfo(" 2");
+ NeedFixup = false;
+ }
+ }
+ if(NeedFixup)
+ WriteLineInfo();
+ break;
+ }
+ case tok::pp_pragma: {
+ StringRef Identifier = NextIdentifierName(RawToken);
+ if (Identifier == "clang" || Identifier == "GCC") {
+ if (NextIdentifierName(RawToken) == "system_header") {
+ // keep the directive in, commented out
+ CommentOutDirective(HashToken);
+ // update our own type
+ Type = SM.getFileCharacteristic(RawToken.getLocation());
+ WriteLineInfo();
+ }
+ } else if (Identifier == "once") {
+ // keep the directive in, commented out
+ CommentOutDirective(HashToken);
+ WriteLineInfo();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ RawLex->setParsingPreprocessorDirective(false);
+ RawLex->SetCommentRetentionState(false);
+ }
+ RawLex->LexFromRawLexer(RawToken);
+ }
+ OutputContentUpTo(SM.getFileIDSize(FileId), true);
+ return true;
+}
+
+void IncludeRewriter::File::DetectEOL() {
+ // detect what line endings the file uses, so that added content does not mix
+ // the style
+ const char* Pos = strchr(FromFile->getBufferStart(), '\n');
+ if (Pos == NULL)
+ EOL = "\n";
+ else if (Pos+1 < FromFile->getBufferEnd() && *(Pos+1) == '\r')
+ EOL = "\n\r";
+ else if (Pos-1 >= FromFile->getBufferStart() && *(Pos+1) == '\r')
+ EOL = "\r\n";
+ else
+ EOL = "\n";
+}
+
+void IncludeRewriter::File::WriteLineInfo(StringRef Extra) {
+ if (Rewriter->DisableLineMarkers) {
+ OS << EOL; // Still need to at least separate lines.
+ return;
+ }
+ // Emit #line directives or GNU line markers depending on what mode we're in.
+ if (Rewriter->UseLineDirective) {
+ OS << "#line" << ' ' << Line << ' ' << '"' << FileName << '"';
+ } else {
+ OS << '#' << ' ' << Line << ' ' << '"' << FileName << '"';
+ if (!Extra.empty())
+ OS << Extra;
+ if (Type == SrcMgr::C_System)
+ OS << " 3";
+ else if (Type == SrcMgr::C_ExternCSystem)
+ OS << " 3 4";
+ }
+ OS << EOL;
+}
+
+inline unsigned IncludeRewriter::File::CountNewLines(const char* Pos, int Len) {
+ const char* End = Pos + Len;
+ unsigned Lines = 0;
+ --Pos;
+ while ((Pos = static_cast<const char*>(memchr(Pos + 1, '\n', End - Pos - 1))))
+ ++Lines;
+ return Lines;
+}
+
+/// Copies next not yet written file content up (and not including) to writeEnd.
+void IncludeRewriter::File::OutputContentUpTo(unsigned WriteEnd,
+ bool EnsureNewline) {
+ if (WriteEnd > NextToWrite) {
+ OS.write(FromFile->getBufferStart() + NextToWrite, WriteEnd - NextToWrite);
+ // count lines manually, it's faster than getPresumedLoc()
+ Line += CountNewLines(FromFile->getBufferStart() + NextToWrite,
+ WriteEnd - NextToWrite);
+ if (EnsureNewline) {
+ char LastChar = FromFile->getBufferStart()[WriteEnd - 1];
+ if (LastChar != '\n' && LastChar != '\r')
+ OS << EOL;
+ }
+ NextToWrite = WriteEnd;
+ }
+}
+
+void IncludeRewriter::File::CommentOutDirective(const Token& StartToken) {
+ OutputContentUpTo(SM.getFileOffset(StartToken.getLocation()));
+ Token DirectiveToken;
+ do {
+ RawLex->LexFromRawLexer(DirectiveToken);
+ } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof));
+ OS << "#if 0 /* expanded by -frewrite-includes */" << EOL;
+ OutputContentUpTo(SM.getFileOffset(DirectiveToken.getLocation())
+ + DirectiveToken.getLength());
+ OS << "#endif /* expanded by -frewrite-includes */" << EOL;
+}
+
+StringRef IncludeRewriter::File::NextIdentifierName(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();
+}
+
+/// RewriteIncludesInInput - Implement -frewrite-includes mode.
+void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
+ const PreprocessorOutputOptions &Opts) {
+ IncludeRewriter* Rewrite = new IncludeRewriter(PP, *OS, Opts);
+ 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.
+ // TODO: 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();
+ OS->flush();
+}
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes1.h tools/clang/test/Frontend/Inputs/rewrite-includes1.h
new file mode 100644
index 0000000..1b6c80d
--- /dev/null
+++ tools/clang/test/Frontend/Inputs/rewrite-includes1.h
@@ -0,0 +1,3 @@
+#pragma clang system_header
+included_line1
+#include "rewrite-includes2.h"
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes2.h tools/clang/test/Frontend/Inputs/rewrite-includes2.h
new file mode 100644
index 0000000..1114e51
--- /dev/null
+++ tools/clang/test/Frontend/Inputs/rewrite-includes2.h
@@ -0,0 +1 @@
+included_line2
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes3.h tools/clang/test/Frontend/Inputs/rewrite-includes3.h
new file mode 100644
index 0000000..3757bc8
--- /dev/null
+++ tools/clang/test/Frontend/Inputs/rewrite-includes3.h
@@ -0,0 +1 @@
+included_line3
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes4.h tools/clang/test/Frontend/Inputs/rewrite-includes4.h
new file mode 100644
index 0000000..b4e25d2
--- /dev/null
+++ tools/clang/test/Frontend/Inputs/rewrite-includes4.h
@@ -0,0 +1 @@
+included_line4
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes5.h tools/clang/test/Frontend/Inputs/rewrite-includes5.h
new file mode 100644
index 0000000..934bf41
--- /dev/null
+++ tools/clang/test/Frontend/Inputs/rewrite-includes5.h
@@ -0,0 +1 @@
+included_line5
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes6.h tools/clang/test/Frontend/Inputs/rewrite-includes6.h
new file mode 100644
index 0000000..c18e501
--- /dev/null
+++ tools/clang/test/Frontend/Inputs/rewrite-includes6.h
@@ -0,0 +1,2 @@
+#pragma once
+included_line6
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes7.h tools/clang/test/Frontend/Inputs/rewrite-includes7.h
new file mode 100644
index 0000000..85428fd
--- /dev/null
+++ tools/clang/test/Frontend/Inputs/rewrite-includes7.h
@@ -0,0 +1,4 @@
+#ifndef REWRITE_INCLUDES7_H
+#define REWRITE_INCLUDES7_H
+included_line7
+#endif
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes8.h tools/clang/test/Frontend/Inputs/rewrite-includes8.h
new file mode 100644
index 0000000..7ab5fd9
--- /dev/null
+++ tools/clang/test/Frontend/Inputs/rewrite-includes8.h
@@ -0,0 +1 @@
+included_line8
\ No newline at end of file
diff --git tools/clang/test/Frontend/Inputs/rewrite-includes9.h tools/clang/test/Frontend/Inputs/rewrite-includes9.h
new file mode 100644
index 0000000..e69de29
diff --git tools/clang/test/Frontend/rewrite-includes.c tools/clang/test/Frontend/rewrite-includes.c
new file mode 100644
index 0000000..67a8802
--- /dev/null
+++ tools/clang/test/Frontend/rewrite-includes.c
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -verify -E -frewrite-includes -DFIRST -I %S/Inputs %s -o - | 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 */
+#include "rewrite-includes7.h"
+#include "rewrite-includes7.h"
+#include "rewrite-includes8.h" // no trailing \n in file
+#include "rewrite-includes9.h" // empty file
+// ENDCOMPARE
+
+// CHECK: {{^}}// STARTCOMPARE{{$}}
+// CHECK-NEXT: {{^}}#define A(a,b) a ## b{{$}}
+// CHECK-NEXT: {{^}}A(1,2){{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes1.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}/Inputs/rewrite-includes1.h" 1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#pragma clang system_header{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 2 "{{.*}}/Inputs/rewrite-includes1.h" 3{{$}}
+// CHECK-NEXT: {{^}}included_line1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes2.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}/Inputs/rewrite-includes2.h" 1 3{{$}}
+// CHECK-NEXT: {{^}}included_line2{{$}}
+// CHECK-NEXT: {{^}}# 4 "{{.*}}/Inputs/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 -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include HEADER{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}/Inputs/rewrite-includes3.h" 1{{$}}
+// CHECK-NEXT: {{^}}included_line3{{$}}
+// CHECK-NEXT: {{^}}# 10 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#else{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes4.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 12 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#/**/include /**/ "rewrite-includes5.h" /**/ {{\\}}{{$}}
+// CHECK-NEXT: {{^}} {{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}/Inputs/rewrite-includes5.h" 1{{$}}
+// CHECK-NEXT: {{^}}included_line5{{$}}
+// CHECK-NEXT: {{^}}# 15 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes6.h" // comment{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}/Inputs/rewrite-includes6.h" 1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#pragma once{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 2 "{{.*}}/Inputs/rewrite-includes6.h"{{$}}
+// CHECK-NEXT: {{^}}included_line6{{$}}
+// CHECK-NEXT: {{^}}# 16 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}} {{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes6.h" /* comment{{$}}
+// CHECK-NEXT: {{^}} continues */{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 19 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes7.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}/Inputs/rewrite-includes7.h" 1{{$}}
+// CHECK-NEXT: {{^}}#ifndef REWRITE_INCLUDES7_H{{$}}
+// CHECK-NEXT: {{^}}#define REWRITE_INCLUDES7_H{{$}}
+// CHECK-NEXT: {{^}}included_line7{{$}}
+// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}# 20 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes7.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 21 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes8.h" // no trailing \n in file{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}/Inputs/rewrite-includes8.h" 1{{$}}
+// CHECK-NEXT: {{^}}included_line8{{$}}
+// CHECK-NEXT: {{^}}# 22 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes9.h" // empty file{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -frewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}/Inputs/rewrite-includes9.h" 1{{$}}
+// CHECK-NEXT: {{^}}# 23 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}// ENDCOMPARE{{$}}