Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -604,6 +604,9 @@ OPENCL_EXTENSION_DECLS = 59, MODULAR_CODEGEN_DECLS = 60, + + /// \brief Record code for \#pragma pack options. + PACK_PRAGMA_OPTIONS = 61, }; /// \brief Record types used within a source manager block. Index: include/clang/Serialization/ASTReader.h =================================================================== --- include/clang/Serialization/ASTReader.h +++ include/clang/Serialization/ASTReader.h @@ -811,6 +811,17 @@ int PragmaMSPointersToMembersState = -1; SourceLocation PointersToMembersPragmaLocation; + /// \brief The pragma pack state. + Optional PragmaPackCurrentValue; + SourceLocation PragmaPackCurrentLocation; + struct PragmaPackStackEntry { + unsigned Value; + SourceLocation Location; + StringRef SlotLabel; + }; + llvm::SmallVector PragmaPackStack; + llvm::SmallVector PragmaPackStrings; + /// \brief The OpenCL extension settings. OpenCLOptions OpenCLExtensions; Index: include/clang/Serialization/ASTWriter.h =================================================================== --- include/clang/Serialization/ASTWriter.h +++ include/clang/Serialization/ASTWriter.h @@ -485,6 +485,7 @@ void WriteOptimizePragmaOptions(Sema &SemaRef); void WriteMSStructPragmaOptions(Sema &SemaRef); void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef); + void WritePackPragmaOptions(Sema &SemaRef); void WriteModuleFileExtension(Sema &SemaRef, ModuleFileExtensionWriter &Writer); Index: lib/Sema/SemaAttr.cpp =================================================================== --- lib/Sema/SemaAttr.cpp +++ lib/Sema/SemaAttr.cpp @@ -215,6 +215,7 @@ ValueType Value) { if (Action == PSK_Reset) { CurrentValue = DefaultValue; + CurrentPragmaLocation = PragmaLocation; return; } if (Action & PSK_Push) Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -3298,6 +3298,28 @@ } ForceCUDAHostDeviceDepth = Record[0]; break; + + case PACK_PRAGMA_OPTIONS: { + if (Record.size() < 3) { + Error("invalid pragma pack record"); + return Failure; + } + PragmaPackCurrentValue = Record[0]; + PragmaPackCurrentLocation = ReadSourceLocation(F, Record[1]); + unsigned NumStackEntries = Record[2]; + unsigned Idx = 3; + // Reset the stack when importing a new module. + PragmaPackStack.clear(); + for (unsigned I = 0; I < NumStackEntries; ++I) { + PragmaPackStackEntry Entry; + Entry.Value = Record[Idx++]; + Entry.Location = ReadSourceLocation(F, Record[Idx++]); + PragmaPackStrings.push_back(ReadString(Record, Idx)); + Entry.SlotLabel = PragmaPackStrings.back(); + PragmaPackStack.push_back(Entry); + } + break; + } } } } @@ -7411,6 +7433,34 @@ PointersToMembersPragmaLocation); } SemaObj->ForceCUDAHostDeviceDepth = ForceCUDAHostDeviceDepth; + + if (PragmaPackCurrentValue) { + // The bottom of the stack might have a default value. It must be adjusted + // to the current value to ensure that the packing state is preserved after + // popping entries that were included/imported from a PCH/module. + bool DropFirst = false; + if (!PragmaPackStack.empty() && + PragmaPackStack.front().Location.isInvalid()) { + assert(PragmaPackStack.front().Value == SemaObj->PackStack.DefaultValue && + "Expected a default alignment value"); + SemaObj->PackStack.Stack.emplace_back( + PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue, + SemaObj->PackStack.CurrentPragmaLocation); + 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); + if (PragmaPackCurrentLocation.isInvalid()) { + assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue && + "Expected a default alignment value"); + // Keep the current values. + } else { + SemaObj->PackStack.CurrentValue = *PragmaPackCurrentValue; + SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation; + } + } } IdentifierInfo *ASTReader::get(StringRef Name) { Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -4168,6 +4168,20 @@ Stream.EmitRecord(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS, Record); } +/// \brief Write the state of 'pragma pack' at the end of the module. +void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) { + RecordData Record; + Record.push_back(SemaRef.PackStack.CurrentValue); + AddSourceLocation(SemaRef.PackStack.CurrentPragmaLocation, Record); + Record.push_back(SemaRef.PackStack.Stack.size()); + for (const auto &StackEntry : SemaRef.PackStack.Stack) { + Record.push_back(StackEntry.Value); + AddSourceLocation(StackEntry.PragmaLocation, Record); + AddString(StackEntry.StackSlotLabel, Record); + } + Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record); +} + void ASTWriter::WriteModuleFileExtension(Sema &SemaRef, ModuleFileExtensionWriter &Writer) { // Enter the extension block. @@ -4858,6 +4872,7 @@ WriteMSStructPragmaOptions(SemaRef); WriteMSPointersToMembersPragmaOptions(SemaRef); } + WritePackPragmaOptions(SemaRef); // Some simple statistics RecordData::value_type Record[] = { Index: test/Modules/Inputs/module.map =================================================================== --- test/Modules/Inputs/module.map +++ test/Modules/Inputs/module.map @@ -265,6 +265,22 @@ header "diag_pragma.h" } +module pragma_pack_set { + header "pragma_pack_set.h" +} + +module pragma_pack_push { + header "pragma_pack_push.h" +} + +module pragma_pack_empty { + header "empty.h" +} + +module pragma_pack_reset_push { + header "pragma_pack_reset_push.h" +} + module dummy { header "dummy.h" } Index: test/Modules/Inputs/pragma_pack_push.h =================================================================== --- /dev/null +++ test/Modules/Inputs/pragma_pack_push.h @@ -0,0 +1,6 @@ + +#pragma pack (push, 4) +#pragma pack (push, 2) +#pragma pack (push, 1) +#pragma pack (pop) + Index: test/Modules/Inputs/pragma_pack_reset_push.h =================================================================== --- /dev/null +++ test/Modules/Inputs/pragma_pack_reset_push.h @@ -0,0 +1,4 @@ + +#pragma pack () +#pragma pack (push, 4) + Index: test/Modules/Inputs/pragma_pack_set.h =================================================================== --- /dev/null +++ test/Modules/Inputs/pragma_pack_set.h @@ -0,0 +1,3 @@ + +#pragma pack (1) + Index: test/Modules/pragma-pack.c =================================================================== --- /dev/null +++ test/Modules/pragma-pack.c @@ -0,0 +1,35 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=pragma_pack_set %S/Inputs/module.map +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=pragma_pack_push %S/Inputs/module.map +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=pragma_pack_empty %S/Inputs/module.map +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=pragma_pack_reset_push %S/Inputs/module.map +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c -verify -fmodules-cache-path=%t -I %S/Inputs %s +// FIXME: When we have a syntax for modules in C, use that. + +@import pragma_pack_set; + +#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 1}} +#pragma pack (pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} + +@import pragma_pack_push; + +#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 2}} +#pragma pack (pop) +#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 4}} +#pragma pack (pop) +#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 1}} +#pragma pack (pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} + +#pragma pack (16) + +@import pragma_pack_empty; + +#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 16}} +#pragma pack (pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} + +@import pragma_pack_reset_push; + +#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 4}} +#pragma pack (pop) +#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 8}} + Index: test/PCH/pragma-pack.c =================================================================== --- /dev/null +++ test/PCH/pragma-pack.c @@ -0,0 +1,90 @@ +// 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 + +// 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 + +#ifndef HEADER +#define HEADER + +#ifdef SET +#pragma pack(1) +#endif + +#ifdef RESET +#pragma pack(2) +#pragma pack () +#endif + +#ifdef PUSH +#pragma pack(1) +#pragma pack (push, 2) +#endif + +#ifdef PUSH_POP +#pragma pack (push, 4) +#pragma pack (push, 2) +#pragma pack (pop) +#endif + +#ifdef PUSH_POP_LABEL +#pragma pack (push, a, 4) +#pragma pack (push, b, 1) +#pragma pack (push, c, 2) +#pragma pack (pop, b) +#endif + +#else + +#ifdef SET +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 1}} +#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} +#endif + +#ifdef RESET +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}} +#pragma () +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}} +#endif + +#ifdef PUSH +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 2}} +#pragma pack(pop) +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 1}} +#pragma pack () +#pragma pack (show) // expected-warning {{value of #pragma pack(show) == 8}} +#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} +#endif + +#ifdef PUSH_POP +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 4}} +#pragma pack(pop) +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}} +#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} +#endif + +#ifdef PUSH_POP_LABEL +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 4}} +#pragma pack(pop, c) +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 4}} +#pragma pack(pop, a) +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}} +#pragma pack(pop) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} +#pragma pack(pop, b) // expected-warning {{#pragma pack(pop, ...) failed: stack empty}} +#pragma pack(show) // expected-warning {{value of #pragma pack(show) == 8}} +#endif + +#endif