summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2017-07-19 11:30:41 +0000
committerAlex Lorenz <arphaman@gmail.com>2017-07-19 11:30:41 +0000
commit62df60052322a90fbf4c3764607df6f457f7f0d9 (patch)
treeaaea30dd8bf49f240505497f3e70ba2ccfc9ec60
parent1bbf8120e4da5e5f32c4b6c5e29b5df8607291bf (diff)
Recommit r308327: Add a warning for missing '#pragma pack (pop)'
and suspicious uses of '#pragma pack' in included files This commit adds a new -Wpragma-pack warning. It warns in the following cases: - When a translation unit is missing terminating #pragma pack (pop) directives. - When entering an included file if the current alignment value as determined by '#pragma pack' directives is different from the default alignment value. - When leaving an included file that changed the state of the current alignment value. rdar://10184173 Differential Revision: https://reviews.llvm.org/D35484 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@308441 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td10
-rw-r--r--include/clang/Lex/PPCallbacks.h6
-rw-r--r--include/clang/Sema/Sema.h31
-rw-r--r--include/clang/Serialization/ASTReader.h1
-rw-r--r--lib/Parse/ParsePragma.cpp9
-rw-r--r--lib/Sema/Sema.cpp54
-rw-r--r--lib/Sema/SemaAttr.cpp37
-rw-r--r--lib/Serialization/ASTReader.cpp6
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--test/OpenMP/declare_simd_messages.cpp2
-rw-r--r--test/PCH/pragma-pack.c30
-rw-r--r--test/PCH/suspicious-pragma-pack.c8
-rw-r--r--test/Parser/pragma-options.c2
-rw-r--r--test/Parser/pragma-options.cpp2
-rw-r--r--test/Parser/pragma-pack.c2
-rw-r--r--test/Sema/Inputs/pragma-pack1.h23
-rw-r--r--test/Sema/Inputs/pragma-pack2.h6
-rw-r--r--test/Sema/pragma-pack.c5
-rw-r--r--test/Sema/suspicious-pragma-pack.c44
-rw-r--r--test/SemaObjC/Inputs/empty.h1
-rw-r--r--test/SemaObjC/suspicious-pragma-pack.m6
22 files changed, 259 insertions, 30 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 53d8f36ecd..1dbe746f60 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -469,8 +469,9 @@ def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>;
def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">;
+def PragmaPack : DiagGroup<"pragma-pack">;
def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas,
- PragmaClangAttribute]>;
+ PragmaClangAttribute, PragmaPack]>;
def UnknownWarningOption : DiagGroup<"unknown-warning-option">;
def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index af14638e1d..a9b76a345d 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -712,6 +712,16 @@ def err_pragma_options_align_mac68k_target_unsupported : Error<
def warn_pragma_pack_invalid_alignment : Warning<
"expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">,
InGroup<IgnoredPragmas>;
+def warn_pragma_pack_non_default_at_include : Warning<
+ "non-default #pragma pack value might change the alignment of struct or "
+ "union members in the included file">, InGroup<PragmaPack>;
+def warn_pragma_pack_modified_after_include : Warning<
+ "the current #pragma pack aligment value is modified in the included "
+ "file">, InGroup<PragmaPack>;
+def warn_pragma_pack_no_pop_eof : Warning<"unterminated "
+ "'#pragma pack (push, ...)' at end of file">, InGroup<PragmaPack>;
+def note_pragma_pack_here : Note<
+ "previous '#pragma pack' directive that modifies alignment is here">;
// Follow the Microsoft implementation.
def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">;
def warn_pragma_pack_pop_identifer_and_alignment : Warning<
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index 81c3bd7d14..c1e1a54960 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -381,6 +381,12 @@ public:
Second->Ident(Loc, str);
}
+ void PragmaDirective(SourceLocation Loc,
+ PragmaIntroducerKind Introducer) override {
+ First->PragmaDirective(Loc, Introducer);
+ Second->PragmaDirective(Loc, Introducer);
+ }
+
void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
StringRef Str) override {
First->PragmaComment(Loc, Kind, Str);
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 5a70854570..957460f4b3 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -208,6 +208,7 @@ namespace sema {
class FunctionScopeInfo;
class LambdaScopeInfo;
class PossiblyUnreachableDiag;
+ class SemaPPCallbacks;
class TemplateDeductionInfo;
}
@@ -381,11 +382,12 @@ public:
llvm::StringRef StackSlotLabel;
ValueType Value;
SourceLocation PragmaLocation;
- Slot(llvm::StringRef StackSlotLabel,
- ValueType Value,
- SourceLocation PragmaLocation)
- : StackSlotLabel(StackSlotLabel), Value(Value),
- PragmaLocation(PragmaLocation) {}
+ SourceLocation PragmaPushLocation;
+ Slot(llvm::StringRef StackSlotLabel, ValueType Value,
+ SourceLocation PragmaLocation, SourceLocation PragmaPushLocation)
+ : StackSlotLabel(StackSlotLabel), Value(Value),
+ PragmaLocation(PragmaLocation),
+ PragmaPushLocation(PragmaPushLocation) {}
};
void Act(SourceLocation PragmaLocation,
PragmaMsStackAction Action,
@@ -416,6 +418,8 @@ public:
explicit PragmaStack(const ValueType &Default)
: DefaultValue(Default), CurrentValue(Default) {}
+ bool hasValue() const { return CurrentValue != DefaultValue; }
+
SmallVector<Slot, 2> Stack;
ValueType DefaultValue; // Value used for PSK_Reset action.
ValueType CurrentValue;
@@ -437,6 +441,8 @@ public:
// Sentinel to represent when the stack is set to mac68k alignment.
static const unsigned kMac68kAlignmentSentinel = ~0U;
PragmaStack<unsigned> PackStack;
+ // The current #pragma pack values and locations at each #include.
+ SmallVector<std::pair<unsigned, SourceLocation>, 8> PackIncludeStack;
// Segment #pragmas.
PragmaStack<StringLiteral *> DataSegStack;
PragmaStack<StringLiteral *> BSSSegStack;
@@ -8182,6 +8188,15 @@ public:
void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
StringRef SlotLabel, Expr *Alignment);
+ enum class PragmaPackDiagnoseKind {
+ NonDefaultStateAtInclude,
+ ChangedStateAtExit
+ };
+
+ void DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
+ SourceLocation IncludeLoc);
+ void DiagnoseUnterminatedPragmaPack();
+
/// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off].
void ActOnPragmaMSStruct(PragmaMSStructKind Kind);
@@ -10383,6 +10398,12 @@ private:
IdentifierInfo *Ident_NSError = nullptr;
+ /// \brief The handler for the FileChanged preprocessor events.
+ ///
+ /// Used for diagnostics that implement custom semantic analysis for #include
+ /// directives, like -Wpragma-pack.
+ sema::SemaPPCallbacks *SemaPPCallbackHandler;
+
protected:
friend class Parser;
friend class InitializationSequence;
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index eafa051758..19f0b81913 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -825,6 +825,7 @@ private:
struct PragmaPackStackEntry {
unsigned Value;
SourceLocation Location;
+ SourceLocation PushLocation;
StringRef SlotLabel;
};
llvm::SmallVector<PragmaPackStackEntry, 2> PragmaPackStack;
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 262743756a..c5215ffcee 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -422,15 +422,20 @@ void Parser::HandlePragmaPack() {
assert(Tok.is(tok::annot_pragma_pack));
PragmaPackInfo *Info =
static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
- SourceLocation PragmaLoc = ConsumeAnnotationToken();
+ SourceLocation PragmaLoc = Tok.getLocation();
ExprResult Alignment;
if (Info->Alignment.is(tok::numeric_constant)) {
Alignment = Actions.ActOnNumericConstant(Info->Alignment);
- if (Alignment.isInvalid())
+ if (Alignment.isInvalid()) {
+ ConsumeAnnotationToken();
return;
+ }
}
Actions.ActOnPragmaPack(PragmaLoc, Info->Action, Info->SlotLabel,
Alignment.get());
+ // Consume the token after processing the pragma to enable pragma-specific
+ // #include warnings.
+ ConsumeAnnotationToken();
}
void Parser::HandlePragmaMSStruct() {
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 6f0db6ce1c..40ffa09de1 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -70,6 +70,49 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
PushDeclContext(S, Context.getTranslationUnitDecl());
}
+namespace clang {
+namespace sema {
+
+class SemaPPCallbacks : public PPCallbacks {
+ Sema *S = nullptr;
+ llvm::SmallVector<SourceLocation, 8> IncludeStack;
+
+public:
+ void set(Sema &S) { this->S = &S; }
+
+ void reset() { S = nullptr; }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override {
+ if (!S)
+ return;
+ switch (Reason) {
+ case EnterFile: {
+ SourceManager &SM = S->getSourceManager();
+ SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc));
+ if (IncludeLoc.isValid()) {
+ IncludeStack.push_back(IncludeLoc);
+ S->DiagnoseNonDefaultPragmaPack(
+ Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc);
+ }
+ break;
+ }
+ case ExitFile:
+ if (!IncludeStack.empty())
+ S->DiagnoseNonDefaultPragmaPack(
+ Sema::PragmaPackDiagnoseKind::ChangedStateAtExit,
+ IncludeStack.pop_back_val());
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+} // end namespace sema
+} // end namespace clang
+
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
: ExternalSource(nullptr), isMultiplexExternalSource(false),
@@ -122,6 +165,12 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
// Initilization of data sharing attributes stack for OpenMP
InitDataSharingAttributesStack();
+
+ std::unique_ptr<sema::SemaPPCallbacks> Callbacks =
+ llvm::make_unique<sema::SemaPPCallbacks>();
+ SemaPPCallbackHandler = Callbacks.get();
+ PP.addPPCallbacks(std::move(Callbacks));
+ SemaPPCallbackHandler->set(*this);
}
void Sema::addImplicitTypedef(StringRef Name, QualType T) {
@@ -306,6 +355,10 @@ Sema::~Sema() {
// Destroys data sharing attributes stack for OpenMP
DestroyDataSharingAttributesStack();
+ // Detach from the PP callback handler which outlives Sema since it's owned
+ // by the preprocessor.
+ SemaPPCallbackHandler->reset();
+
assert(DelayedTypos.empty() && "Uncorrected typos!");
}
@@ -766,6 +819,7 @@ void Sema::ActOnEndOfTranslationUnit() {
CheckDelayedMemberExceptionSpecs();
}
+ DiagnoseUnterminatedPragmaPack();
DiagnoseUnterminatedPragmaAttribute();
// All delayed member exception specs should be checked or we end up accepting
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 8c13ead644..7193450220 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -202,6 +202,40 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal);
}
+void Sema::DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
+ SourceLocation IncludeLoc) {
+ if (Kind == PragmaPackDiagnoseKind::NonDefaultStateAtInclude) {
+ SourceLocation PrevLocation = PackStack.CurrentPragmaLocation;
+ // Warn about non-default alignment at #includes (without redundant
+ // warnings for the same directive in nested includes).
+ if (PackStack.hasValue() &&
+ (PackIncludeStack.empty() ||
+ PackIncludeStack.back().second != PrevLocation)) {
+ Diag(IncludeLoc, diag::warn_pragma_pack_non_default_at_include);
+ Diag(PrevLocation, diag::note_pragma_pack_here);
+ }
+ PackIncludeStack.push_back(
+ {PackStack.CurrentValue,
+ PackStack.hasValue() ? PrevLocation : SourceLocation()});
+ return;
+ }
+
+ assert(Kind == PragmaPackDiagnoseKind::ChangedStateAtExit && "invalid kind");
+ unsigned PreviousValue = PackIncludeStack.pop_back_val().first;
+ // Warn about modified alignment after #includes.
+ if (PreviousValue != PackStack.CurrentValue) {
+ Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include);
+ Diag(PackStack.CurrentPragmaLocation, diag::note_pragma_pack_here);
+ }
+}
+
+void Sema::DiagnoseUnterminatedPragmaPack() {
+ if (PackStack.Stack.empty())
+ return;
+ for (const auto &StackSlot : llvm::reverse(PackStack.Stack))
+ Diag(StackSlot.PragmaPushLocation, diag::warn_pragma_pack_no_pop_eof);
+}
+
void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
MSStructPragmaOn = (Kind == PMSST_ON);
}
@@ -249,7 +283,8 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
return;
}
if (Action & PSK_Push)
- Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation));
+ Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation,
+ PragmaLocation);
else if (Action & PSK_Pop) {
if (!StackSlotLabel.empty()) {
// If we've got a label, try to find it and jump there.
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 50be74f6bf..a384d051d6 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -3384,6 +3384,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
PragmaPackStackEntry Entry;
Entry.Value = Record[Idx++];
Entry.Location = ReadSourceLocation(F, Record[Idx++]);
+ Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]);
PragmaPackStrings.push_back(ReadString(Record, Idx));
Entry.SlotLabel = PragmaPackStrings.back();
PragmaPackStack.push_back(Entry);
@@ -7579,13 +7580,14 @@ void ASTReader::UpdateSema() {
"Expected a default alignment value");
SemaObj->PackStack.Stack.emplace_back(
PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue,
- SemaObj->PackStack.CurrentPragmaLocation);
+ SemaObj->PackStack.CurrentPragmaLocation,
+ PragmaPackStack.front().PushLocation);
DropFirst = true;
}
for (const auto &Entry :
llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0))
SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value,
- Entry.Location);
+ Entry.Location, Entry.PushLocation);
if (PragmaPackCurrentLocation.isInvalid()) {
assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue &&
"Expected a default alignment value");
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index a875e627bd..9a739579b3 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -4295,6 +4295,7 @@ void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) {
for (const auto &StackEntry : SemaRef.PackStack.Stack) {
Record.push_back(StackEntry.Value);
AddSourceLocation(StackEntry.PragmaLocation, Record);
+ AddSourceLocation(StackEntry.PragmaPushLocation, Record);
AddString(StackEntry.StackSlotLabel, Record);
}
Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record);
diff --git a/test/OpenMP/declare_simd_messages.cpp b/test/OpenMP/declare_simd_messages.cpp
index 15971eb14d..af46283f9a 100644
--- a/test/OpenMP/declare_simd_messages.cpp
+++ b/test/OpenMP/declare_simd_messages.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c++ -std=c++11 -fms-extensions %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c++ -std=c++11 -fms-extensions -Wno-pragma-pack %s
// expected-error@+1 {{expected an OpenMP directive}}
#pragma omp declare
diff --git a/test/PCH/pragma-pack.c b/test/PCH/pragma-pack.c
index 47a5570023..7b45e045b3 100644
--- a/test/PCH/pragma-pack.c
+++ b/test/PCH/pragma-pack.c
@@ -1,21 +1,21 @@
// Test this without pch.
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DSET
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DRESET
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH_POP
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH_POP_LABEL
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DSET
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DRESET
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH_POP
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH_POP_LABEL
// Test with pch.
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DSET -emit-pch -o %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DSET -verify -include-pch %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DRESET -emit-pch -o %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DRESET -verify -include-pch %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH -emit-pch -o %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH -verify -include-pch %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP -emit-pch -o %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP -verify -include-pch %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP_LABEL -emit-pch -o %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP_LABEL -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DSET -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DSET -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DRESET -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DRESET -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP_LABEL -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP_LABEL -verify -include-pch %t
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/suspicious-pragma-pack.c b/test/PCH/suspicious-pragma-pack.c
new file mode 100644
index 0000000000..01a66af34b
--- /dev/null
+++ b/test/PCH/suspicious-pragma-pack.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -verify -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -verify -include-pch %t
+
+#ifndef HEADER
+#define HEADER
+#pragma pack (push, 1)
+#endif
+// expected-warning@-2 {{unterminated '#pragma pack (push, ...)' at end of file}}
diff --git a/test/Parser/pragma-options.c b/test/Parser/pragma-options.c
index d168a2751a..a35f0b087e 100644
--- a/test/Parser/pragma-options.c
+++ b/test/Parser/pragma-options.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -Wno-pragma-pack -fsyntax-only -verify %s
/* expected-warning {{expected 'align' following '#pragma options'}} */ #pragma options
/* expected-warning {{expected '=' following '#pragma options align'}} */ #pragma options align
diff --git a/test/Parser/pragma-options.cpp b/test/Parser/pragma-options.cpp
index 84cd38dfb3..8f5a2152c7 100644
--- a/test/Parser/pragma-options.cpp
+++ b/test/Parser/pragma-options.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -Wno-pragma-pack -fsyntax-only -verify %s
// expected-no-diagnostics
class C {
diff --git a/test/Parser/pragma-pack.c b/test/Parser/pragma-pack.c
index 0859f4157c..d2aefaa888 100644
--- a/test/Parser/pragma-pack.c
+++ b/test/Parser/pragma-pack.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-pragma-pack -verify %s
// Note that this puts the expected lines before the directives to work around
// limitations in the -verify mode.
diff --git a/test/Sema/Inputs/pragma-pack1.h b/test/Sema/Inputs/pragma-pack1.h
new file mode 100644
index 0000000000..40e7ad18b2
--- /dev/null
+++ b/test/Sema/Inputs/pragma-pack1.h
@@ -0,0 +1,23 @@
+
+#ifdef SET_FIRST_HEADER
+#pragma pack (16)
+#ifndef SET_SECOND_HEADER
+// expected-note@-2 2 {{previous '#pragma pack' directive that modifies alignment is here}}
+#else
+// expected-note@-4 1 {{previous '#pragma pack' directive that modifies alignment is here}}
+#endif
+// expected-warning@+3 {{non-default #pragma pack value might change the alignment of struct or union members in the included file}}
+#endif
+
+#include "pragma-pack2.h"
+
+#ifdef SET_SECOND_HEADER
+// expected-warning@-3 {{the current #pragma pack aligment value is modified in the included file}}
+#endif
+
+#ifdef PUSH_POP_FIRST_HEADER
+// This is fine, we don't change the current value.
+#pragma pack (push, 4)
+
+#pragma pack (pop)
+#endif
diff --git a/test/Sema/Inputs/pragma-pack2.h b/test/Sema/Inputs/pragma-pack2.h
new file mode 100644
index 0000000000..11036133a1
--- /dev/null
+++ b/test/Sema/Inputs/pragma-pack2.h
@@ -0,0 +1,6 @@
+
+#ifdef SET_SECOND_HEADER
+#pragma pack (8) // expected-note 2 {{previous '#pragma pack' directive that modifies alignment is here}}
+#endif
+
+struct S { int x; };
diff --git a/test/Sema/pragma-pack.c b/test/Sema/pragma-pack.c
index e93ce42148..84a946368f 100644
--- a/test/Sema/pragma-pack.c
+++ b/test/Sema/pragma-pack.c
@@ -25,3 +25,8 @@
#pragma pack(pop, 16)
/* expected-warning {{value of #pragma pack(show) == 16}} */ #pragma pack(show)
+
+// Warn about unbalanced pushes.
+#pragma pack (push,4) // expected-warning {{unterminated '#pragma pack (push, ...)' at end of file}}
+#pragma pack (push) // expected-warning {{unterminated '#pragma pack (push, ...)' at end of file}}
+#pragma pack ()
diff --git a/test/Sema/suspicious-pragma-pack.c b/test/Sema/suspicious-pragma-pack.c
new file mode 100644
index 0000000000..10c4167102
--- /dev/null
+++ b/test/Sema/suspicious-pragma-pack.c
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DSAFE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_HERE -DSAFE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_HERE -DPUSH_SET_HERE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_HERE -DRESET_HERE -DSAFE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_HERE -DSET_FIRST_HEADER -DWARN_MODIFIED_HEADER -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_HERE -DRESET_HERE -DSET_FIRST_HEADER -DWARN_MODIFIED_HEADER -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_HERE -DPUSH_SET_HERE -DSET_FIRST_HEADER -DWARN_MODIFIED_HEADER -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_HERE -DPUSH_SET_HERE -DSET_SECOND_HEADER -DWARN_MODIFIED_HEADER -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_HERE -DPUSH_SET_HERE -DSET_FIRST_HEADER -DSET_SECOND_HEADER -DWARN_MODIFIED_HEADER -verify %s
+
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I %S/Inputs -DPUSH_POP_FIRST_HEADER -DSAFE -verify %s
+
+
+#ifdef SAFE
+// expected-no-diagnostics
+#endif
+
+#ifdef PUSH_HERE
+#pragma pack (push)
+#endif
+
+#ifdef PUSH_SET_HERE
+#pragma pack (push, 4) // expected-note {{previous '#pragma pack' directive that modifies alignment is here}}
+// expected-warning@+8 {{non-default #pragma pack value might change the alignment of struct or union members in the included file}}
+#endif
+
+#ifdef RESET_HERE
+#pragma pack (4)
+#pragma pack () // no warning after reset as the value is default.
+#endif
+
+#include "pragma-pack1.h"
+
+#ifdef WARN_MODIFIED_HEADER
+// expected-warning@-3 {{the current #pragma pack aligment value is modified in the included file}}
+#endif
+
+#ifdef PUSH_SET_HERE
+#pragma pack (pop)
+#endif
+
+#ifdef PUSH_HERE
+#pragma pack (pop)
+#endif
diff --git a/test/SemaObjC/Inputs/empty.h b/test/SemaObjC/Inputs/empty.h
new file mode 100644
index 0000000000..8b1a393741
--- /dev/null
+++ b/test/SemaObjC/Inputs/empty.h
@@ -0,0 +1 @@
+// empty
diff --git a/test/SemaObjC/suspicious-pragma-pack.m b/test/SemaObjC/suspicious-pragma-pack.m
new file mode 100644
index 0000000000..125ce1d4cc
--- /dev/null
+++ b/test/SemaObjC/suspicious-pragma-pack.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -I%S/Inputs -verify %s
+
+#pragma pack (push, 1) // expected-note {{previous '#pragma pack' directive that modifies alignment is here}}
+#import "empty.h" // expected-warning {{non-default #pragma pack value might change the alignment of struct or union members in the included file}}
+
+#pragma pack (pop)