Skip to content

Commit

Permalink
[Serialization] Add support for (de)serializing #pragma pack
Browse files Browse the repository at this point in the history
Serialization of tokens is required when PCH is used with late parsed
templates, including annotation tokens used for pragmas.

This patch implements the serialization for annot_pragma_pack.

Fixes #60543

Differential Revision: https://reviews.llvm.org/D143410
  • Loading branch information
DHowett authored and mikerice1969 committed Feb 7, 2023
1 parent 0fb5d35 commit d27fb5e
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 14 deletions.
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -483,6 +483,12 @@ class Sema final {
PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value)
};

struct PragmaPackInfo {
PragmaMsStackAction Action;
StringRef SlotLabel;
Token Alignment;
};

// #pragma pack and align.
class AlignPackInfo {
public:
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Serialization/ASTReader.h
Expand Up @@ -2236,7 +2236,7 @@ class ASTReader
unsigned &Idx, LocSeq *Seq = nullptr);

// Read a string
static std::string ReadString(const RecordData &Record, unsigned &Idx);
static std::string ReadString(const RecordDataImpl &Record, unsigned &Idx);

// Skip a string
static void SkipString(const RecordData &Record, unsigned &Idx) {
Expand Down
16 changes: 4 additions & 12 deletions clang/lib/Parse/ParsePragma.cpp
Expand Up @@ -665,18 +665,10 @@ void Parser::HandlePragmaVisibility() {
Actions.ActOnPragmaVisibility(VisType, VisLoc);
}

namespace {
struct PragmaPackInfo {
Sema::PragmaMsStackAction Action;
StringRef SlotLabel;
Token Alignment;
};
} // end anonymous namespace

void Parser::HandlePragmaPack() {
assert(Tok.is(tok::annot_pragma_pack));
PragmaPackInfo *Info =
static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
Sema::PragmaPackInfo *Info =
static_cast<Sema::PragmaPackInfo *>(Tok.getAnnotationValue());
SourceLocation PragmaLoc = Tok.getLocation();
ExprResult Alignment;
if (Info->Alignment.is(tok::numeric_constant)) {
Expand Down Expand Up @@ -2110,8 +2102,8 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
return;
}

PragmaPackInfo *Info =
PP.getPreprocessorAllocator().Allocate<PragmaPackInfo>(1);
Sema::PragmaPackInfo *Info =
PP.getPreprocessorAllocator().Allocate<Sema::PragmaPackInfo>(1);
Info->Action = Action;
Info->SlotLabel = SlotLabel;
Info->Alignment = Alignment;
Expand Down
12 changes: 11 additions & 1 deletion clang/lib/Serialization/ASTReader.cpp
Expand Up @@ -1687,6 +1687,16 @@ Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
Tok.setAnnotationValue(static_cast<void *>(Info));
break;
}
case tok::annot_pragma_pack: {
auto *Info = new (PP.getPreprocessorAllocator()) Sema::PragmaPackInfo;
Info->Action = static_cast<Sema::PragmaMsStackAction>(Record[Idx++]);
auto SlotLabel = ReadString(Record, Idx);
Info->SlotLabel =
llvm::StringRef(SlotLabel).copy(PP.getPreprocessorAllocator());
Info->Alignment = ReadToken(F, Record, Idx);
Tok.setAnnotationValue(static_cast<void *>(Info));
break;
}
// Some annotation tokens do not use the PtrData field.
case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_end:
Expand Down Expand Up @@ -9084,7 +9094,7 @@ llvm::APFloat ASTRecordReader::readAPFloat(const llvm::fltSemantics &Sem) {
}

// Read a string
std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) {
std::string ASTReader::ReadString(const RecordDataImpl &Record, unsigned &Idx) {
unsigned Len = Record[Idx++];
std::string Result(Record.data() + Idx, Record.data() + Idx + Len);
Idx += Len;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Serialization/ASTWriter.cpp
Expand Up @@ -4412,6 +4412,14 @@ void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
AddToken(T, Record);
break;
}
case tok::annot_pragma_pack: {
auto *Info =
static_cast<Sema::PragmaPackInfo *>(Tok.getAnnotationValue());
Record.push_back(static_cast<unsigned>(Info->Action));
AddString(Info->SlotLabel, Record);
AddToken(Info->Alignment, Record);
break;
}
// Some annotation tokens do not use the PtrData field.
case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_end:
Expand Down
78 changes: 78 additions & 0 deletions clang/test/PCH/delayed-template-with-pragma-pack.cpp
@@ -0,0 +1,78 @@
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-pch -o %t.pch %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fdelayed-template-parsing -emit-pch -o %t.delayed.pch %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -DMAIN_FILE \
// RUN: -include-pch %t.pch \
// RUN: -emit-llvm -verify -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -DMAIN_FILE -fdelayed-template-parsing \
// RUN: -include-pch %t.delayed.pch \
// RUN: -emit-llvm -verify -o - %s | FileCheck %s

#ifndef MAIN_FILE

extern "C" void consume(int b);

template <int I>
void function() {
#pragma pack(push, 1)
struct packedAt1 {
char a;
unsigned long long b;
char c;
unsigned long long d;
// 18 bytes total
};
#pragma pack(push, slot1, 2)
struct packedAt2 {
char a; // +1 byte of padding
unsigned long long b;
char c; // +1 byte of padding
unsigned long long d;
// 20 bytes total
};
#pragma pack(push, 4)
struct packedAt4 {
char a; // +3 bytes of padding
unsigned long long b;
char c; // +3 bytes of padding
unsigned long long d;
// 24 bytes total
};
#pragma pack(push, 16)
struct packedAt16 {
char a; // +7 bytes of padding
unsigned long long b;
char c; // +7 bytes of padding
unsigned long long d;
// 32 bytes total
};
#pragma pack(pop, slot1) // This should return packing to 1 (established before push(slot1))
struct packedAfterPopBackTo1 {
char a;
unsigned long long b;
char c;
unsigned long long d;
};
#pragma pack(pop)

consume(sizeof(packedAt1)); // 18
consume(sizeof(packedAt2)); // 20
consume(sizeof(packedAt4)); // 24
consume(sizeof(packedAt16)); // 32
consume(sizeof(packedAfterPopBackTo1)); // 18 again
}

#else

// CHECK-LABEL: define linkonce_odr dso_local void @"??$function@$0A@@@YAXXZ"(
// CHECK: call void @consume(i32 noundef 18)
// CHECK-NEXT: call void @consume(i32 noundef 20)
// CHECK-NEXT: call void @consume(i32 noundef 24)
// CHECK-NEXT: call void @consume(i32 noundef 32)
// CHECK-NEXT: call void @consume(i32 noundef 18)
void foo() {
function<0>();
}

// expected-no-diagnostics

#endif

0 comments on commit d27fb5e

Please sign in to comment.