Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 62df600

Browse files
committed
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
1 parent 1bbf812 commit 62df600

22 files changed

+259
-30
lines changed

include/clang/Basic/DiagnosticGroups.td

+2-1
Original file line numberDiff line numberDiff line change
@@ -469,8 +469,9 @@ def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">;
469469
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
470470
def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>;
471471
def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">;
472+
def PragmaPack : DiagGroup<"pragma-pack">;
472473
def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas,
473-
PragmaClangAttribute]>;
474+
PragmaClangAttribute, PragmaPack]>;
474475
def UnknownWarningOption : DiagGroup<"unknown-warning-option">;
475476
def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
476477
def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;

include/clang/Basic/DiagnosticSemaKinds.td

+10
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,16 @@ def err_pragma_options_align_mac68k_target_unsupported : Error<
712712
def warn_pragma_pack_invalid_alignment : Warning<
713713
"expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">,
714714
InGroup<IgnoredPragmas>;
715+
def warn_pragma_pack_non_default_at_include : Warning<
716+
"non-default #pragma pack value might change the alignment of struct or "
717+
"union members in the included file">, InGroup<PragmaPack>;
718+
def warn_pragma_pack_modified_after_include : Warning<
719+
"the current #pragma pack aligment value is modified in the included "
720+
"file">, InGroup<PragmaPack>;
721+
def warn_pragma_pack_no_pop_eof : Warning<"unterminated "
722+
"'#pragma pack (push, ...)' at end of file">, InGroup<PragmaPack>;
723+
def note_pragma_pack_here : Note<
724+
"previous '#pragma pack' directive that modifies alignment is here">;
715725
// Follow the Microsoft implementation.
716726
def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">;
717727
def warn_pragma_pack_pop_identifer_and_alignment : Warning<

include/clang/Lex/PPCallbacks.h

+6
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,12 @@ class PPChainedCallbacks : public PPCallbacks {
381381
Second->Ident(Loc, str);
382382
}
383383

384+
void PragmaDirective(SourceLocation Loc,
385+
PragmaIntroducerKind Introducer) override {
386+
First->PragmaDirective(Loc, Introducer);
387+
Second->PragmaDirective(Loc, Introducer);
388+
}
389+
384390
void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
385391
StringRef Str) override {
386392
First->PragmaComment(Loc, Kind, Str);

include/clang/Sema/Sema.h

+26-5
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ namespace sema {
208208
class FunctionScopeInfo;
209209
class LambdaScopeInfo;
210210
class PossiblyUnreachableDiag;
211+
class SemaPPCallbacks;
211212
class TemplateDeductionInfo;
212213
}
213214

@@ -381,11 +382,12 @@ class Sema {
381382
llvm::StringRef StackSlotLabel;
382383
ValueType Value;
383384
SourceLocation PragmaLocation;
384-
Slot(llvm::StringRef StackSlotLabel,
385-
ValueType Value,
386-
SourceLocation PragmaLocation)
387-
: StackSlotLabel(StackSlotLabel), Value(Value),
388-
PragmaLocation(PragmaLocation) {}
385+
SourceLocation PragmaPushLocation;
386+
Slot(llvm::StringRef StackSlotLabel, ValueType Value,
387+
SourceLocation PragmaLocation, SourceLocation PragmaPushLocation)
388+
: StackSlotLabel(StackSlotLabel), Value(Value),
389+
PragmaLocation(PragmaLocation),
390+
PragmaPushLocation(PragmaPushLocation) {}
389391
};
390392
void Act(SourceLocation PragmaLocation,
391393
PragmaMsStackAction Action,
@@ -416,6 +418,8 @@ class Sema {
416418
explicit PragmaStack(const ValueType &Default)
417419
: DefaultValue(Default), CurrentValue(Default) {}
418420

421+
bool hasValue() const { return CurrentValue != DefaultValue; }
422+
419423
SmallVector<Slot, 2> Stack;
420424
ValueType DefaultValue; // Value used for PSK_Reset action.
421425
ValueType CurrentValue;
@@ -437,6 +441,8 @@ class Sema {
437441
// Sentinel to represent when the stack is set to mac68k alignment.
438442
static const unsigned kMac68kAlignmentSentinel = ~0U;
439443
PragmaStack<unsigned> PackStack;
444+
// The current #pragma pack values and locations at each #include.
445+
SmallVector<std::pair<unsigned, SourceLocation>, 8> PackIncludeStack;
440446
// Segment #pragmas.
441447
PragmaStack<StringLiteral *> DataSegStack;
442448
PragmaStack<StringLiteral *> BSSSegStack;
@@ -8182,6 +8188,15 @@ class Sema {
81828188
void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
81838189
StringRef SlotLabel, Expr *Alignment);
81848190

8191+
enum class PragmaPackDiagnoseKind {
8192+
NonDefaultStateAtInclude,
8193+
ChangedStateAtExit
8194+
};
8195+
8196+
void DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
8197+
SourceLocation IncludeLoc);
8198+
void DiagnoseUnterminatedPragmaPack();
8199+
81858200
/// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off].
81868201
void ActOnPragmaMSStruct(PragmaMSStructKind Kind);
81878202

@@ -10383,6 +10398,12 @@ class Sema {
1038310398

1038410399
IdentifierInfo *Ident_NSError = nullptr;
1038510400

10401+
/// \brief The handler for the FileChanged preprocessor events.
10402+
///
10403+
/// Used for diagnostics that implement custom semantic analysis for #include
10404+
/// directives, like -Wpragma-pack.
10405+
sema::SemaPPCallbacks *SemaPPCallbackHandler;
10406+
1038610407
protected:
1038710408
friend class Parser;
1038810409
friend class InitializationSequence;

include/clang/Serialization/ASTReader.h

+1
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ class ASTReader
825825
struct PragmaPackStackEntry {
826826
unsigned Value;
827827
SourceLocation Location;
828+
SourceLocation PushLocation;
828829
StringRef SlotLabel;
829830
};
830831
llvm::SmallVector<PragmaPackStackEntry, 2> PragmaPackStack;

lib/Parse/ParsePragma.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -422,15 +422,20 @@ void Parser::HandlePragmaPack() {
422422
assert(Tok.is(tok::annot_pragma_pack));
423423
PragmaPackInfo *Info =
424424
static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
425-
SourceLocation PragmaLoc = ConsumeAnnotationToken();
425+
SourceLocation PragmaLoc = Tok.getLocation();
426426
ExprResult Alignment;
427427
if (Info->Alignment.is(tok::numeric_constant)) {
428428
Alignment = Actions.ActOnNumericConstant(Info->Alignment);
429-
if (Alignment.isInvalid())
429+
if (Alignment.isInvalid()) {
430+
ConsumeAnnotationToken();
430431
return;
432+
}
431433
}
432434
Actions.ActOnPragmaPack(PragmaLoc, Info->Action, Info->SlotLabel,
433435
Alignment.get());
436+
// Consume the token after processing the pragma to enable pragma-specific
437+
// #include warnings.
438+
ConsumeAnnotationToken();
434439
}
435440

436441
void Parser::HandlePragmaMSStruct() {

lib/Sema/Sema.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,49 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
7070
PushDeclContext(S, Context.getTranslationUnitDecl());
7171
}
7272

73+
namespace clang {
74+
namespace sema {
75+
76+
class SemaPPCallbacks : public PPCallbacks {
77+
Sema *S = nullptr;
78+
llvm::SmallVector<SourceLocation, 8> IncludeStack;
79+
80+
public:
81+
void set(Sema &S) { this->S = &S; }
82+
83+
void reset() { S = nullptr; }
84+
85+
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
86+
SrcMgr::CharacteristicKind FileType,
87+
FileID PrevFID) override {
88+
if (!S)
89+
return;
90+
switch (Reason) {
91+
case EnterFile: {
92+
SourceManager &SM = S->getSourceManager();
93+
SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc));
94+
if (IncludeLoc.isValid()) {
95+
IncludeStack.push_back(IncludeLoc);
96+
S->DiagnoseNonDefaultPragmaPack(
97+
Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc);
98+
}
99+
break;
100+
}
101+
case ExitFile:
102+
if (!IncludeStack.empty())
103+
S->DiagnoseNonDefaultPragmaPack(
104+
Sema::PragmaPackDiagnoseKind::ChangedStateAtExit,
105+
IncludeStack.pop_back_val());
106+
break;
107+
default:
108+
break;
109+
}
110+
}
111+
};
112+
113+
} // end namespace sema
114+
} // end namespace clang
115+
73116
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
74117
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
75118
: ExternalSource(nullptr), isMultiplexExternalSource(false),
@@ -122,6 +165,12 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
122165

123166
// Initilization of data sharing attributes stack for OpenMP
124167
InitDataSharingAttributesStack();
168+
169+
std::unique_ptr<sema::SemaPPCallbacks> Callbacks =
170+
llvm::make_unique<sema::SemaPPCallbacks>();
171+
SemaPPCallbackHandler = Callbacks.get();
172+
PP.addPPCallbacks(std::move(Callbacks));
173+
SemaPPCallbackHandler->set(*this);
125174
}
126175

127176
void Sema::addImplicitTypedef(StringRef Name, QualType T) {
@@ -306,6 +355,10 @@ Sema::~Sema() {
306355
// Destroys data sharing attributes stack for OpenMP
307356
DestroyDataSharingAttributesStack();
308357

358+
// Detach from the PP callback handler which outlives Sema since it's owned
359+
// by the preprocessor.
360+
SemaPPCallbackHandler->reset();
361+
309362
assert(DelayedTypos.empty() && "Uncorrected typos!");
310363
}
311364

@@ -766,6 +819,7 @@ void Sema::ActOnEndOfTranslationUnit() {
766819
CheckDelayedMemberExceptionSpecs();
767820
}
768821

822+
DiagnoseUnterminatedPragmaPack();
769823
DiagnoseUnterminatedPragmaAttribute();
770824

771825
// All delayed member exception specs should be checked or we end up accepting

lib/Sema/SemaAttr.cpp

+36-1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,40 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
202202
PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal);
203203
}
204204

205+
void Sema::DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
206+
SourceLocation IncludeLoc) {
207+
if (Kind == PragmaPackDiagnoseKind::NonDefaultStateAtInclude) {
208+
SourceLocation PrevLocation = PackStack.CurrentPragmaLocation;
209+
// Warn about non-default alignment at #includes (without redundant
210+
// warnings for the same directive in nested includes).
211+
if (PackStack.hasValue() &&
212+
(PackIncludeStack.empty() ||
213+
PackIncludeStack.back().second != PrevLocation)) {
214+
Diag(IncludeLoc, diag::warn_pragma_pack_non_default_at_include);
215+
Diag(PrevLocation, diag::note_pragma_pack_here);
216+
}
217+
PackIncludeStack.push_back(
218+
{PackStack.CurrentValue,
219+
PackStack.hasValue() ? PrevLocation : SourceLocation()});
220+
return;
221+
}
222+
223+
assert(Kind == PragmaPackDiagnoseKind::ChangedStateAtExit && "invalid kind");
224+
unsigned PreviousValue = PackIncludeStack.pop_back_val().first;
225+
// Warn about modified alignment after #includes.
226+
if (PreviousValue != PackStack.CurrentValue) {
227+
Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include);
228+
Diag(PackStack.CurrentPragmaLocation, diag::note_pragma_pack_here);
229+
}
230+
}
231+
232+
void Sema::DiagnoseUnterminatedPragmaPack() {
233+
if (PackStack.Stack.empty())
234+
return;
235+
for (const auto &StackSlot : llvm::reverse(PackStack.Stack))
236+
Diag(StackSlot.PragmaPushLocation, diag::warn_pragma_pack_no_pop_eof);
237+
}
238+
205239
void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
206240
MSStructPragmaOn = (Kind == PMSST_ON);
207241
}
@@ -249,7 +283,8 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
249283
return;
250284
}
251285
if (Action & PSK_Push)
252-
Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation));
286+
Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation,
287+
PragmaLocation);
253288
else if (Action & PSK_Pop) {
254289
if (!StackSlotLabel.empty()) {
255290
// If we've got a label, try to find it and jump there.

lib/Serialization/ASTReader.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
33843384
PragmaPackStackEntry Entry;
33853385
Entry.Value = Record[Idx++];
33863386
Entry.Location = ReadSourceLocation(F, Record[Idx++]);
3387+
Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]);
33873388
PragmaPackStrings.push_back(ReadString(Record, Idx));
33883389
Entry.SlotLabel = PragmaPackStrings.back();
33893390
PragmaPackStack.push_back(Entry);
@@ -7579,13 +7580,14 @@ void ASTReader::UpdateSema() {
75797580
"Expected a default alignment value");
75807581
SemaObj->PackStack.Stack.emplace_back(
75817582
PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue,
7582-
SemaObj->PackStack.CurrentPragmaLocation);
7583+
SemaObj->PackStack.CurrentPragmaLocation,
7584+
PragmaPackStack.front().PushLocation);
75837585
DropFirst = true;
75847586
}
75857587
for (const auto &Entry :
75867588
llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0))
75877589
SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value,
7588-
Entry.Location);
7590+
Entry.Location, Entry.PushLocation);
75897591
if (PragmaPackCurrentLocation.isInvalid()) {
75907592
assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue &&
75917593
"Expected a default alignment value");

lib/Serialization/ASTWriter.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -4295,6 +4295,7 @@ void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) {
42954295
for (const auto &StackEntry : SemaRef.PackStack.Stack) {
42964296
Record.push_back(StackEntry.Value);
42974297
AddSourceLocation(StackEntry.PragmaLocation, Record);
4298+
AddSourceLocation(StackEntry.PragmaPushLocation, Record);
42984299
AddString(StackEntry.StackSlotLabel, Record);
42994300
}
43004301
Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record);

test/OpenMP/declare_simd_messages.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c++ -std=c++11 -fms-extensions %s
1+
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c++ -std=c++11 -fms-extensions -Wno-pragma-pack %s
22

33
// expected-error@+1 {{expected an OpenMP directive}}
44
#pragma omp declare

test/PCH/pragma-pack.c

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
// Test this without pch.
2-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DSET
3-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DRESET
4-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH
5-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH_POP
6-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -DPUSH_POP_LABEL
2+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DSET
3+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DRESET
4+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH
5+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH_POP
6+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH_POP_LABEL
77

88
// Test with pch.
9-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DSET -emit-pch -o %t
10-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DSET -verify -include-pch %t
11-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DRESET -emit-pch -o %t
12-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DRESET -verify -include-pch %t
13-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH -emit-pch -o %t
14-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH -verify -include-pch %t
15-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP -emit-pch -o %t
16-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP -verify -include-pch %t
17-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP_LABEL -emit-pch -o %t
18-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -DPUSH_POP_LABEL -verify -include-pch %t
9+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DSET -emit-pch -o %t
10+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DSET -verify -include-pch %t
11+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DRESET -emit-pch -o %t
12+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DRESET -verify -include-pch %t
13+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH -emit-pch -o %t
14+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH -verify -include-pch %t
15+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP -emit-pch -o %t
16+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP -verify -include-pch %t
17+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP_LABEL -emit-pch -o %t
18+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP_LABEL -verify -include-pch %t
1919

2020
#ifndef HEADER
2121
#define HEADER

test/PCH/suspicious-pragma-pack.c

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -verify -emit-pch -o %t
2+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -verify -include-pch %t
3+
4+
#ifndef HEADER
5+
#define HEADER
6+
#pragma pack (push, 1)
7+
#endif
8+
// expected-warning@-2 {{unterminated '#pragma pack (push, ...)' at end of file}}

test/Parser/pragma-options.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
1+
// RUN: %clang_cc1 -triple i386-apple-darwin9 -Wno-pragma-pack -fsyntax-only -verify %s
22

33
/* expected-warning {{expected 'align' following '#pragma options'}} */ #pragma options
44
/* expected-warning {{expected '=' following '#pragma options align'}} */ #pragma options align

test/Parser/pragma-options.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
1+
// RUN: %clang_cc1 -triple i386-apple-darwin9 -Wno-pragma-pack -fsyntax-only -verify %s
22
// expected-no-diagnostics
33

44
class C {

test/Parser/pragma-pack.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify %s
1+
// RUN: %clang_cc1 -fsyntax-only -Wno-pragma-pack -verify %s
22

33
// Note that this puts the expected lines before the directives to work around
44
// limitations in the -verify mode.

0 commit comments

Comments
 (0)