forked from OSchip/llvm-project
[MS] Improved implementation of MS stack pragmas (vtordisp, *_seg)
Rework implementation of several MS pragmas that use internal stack: vtordisp, {bss|code|const|data}_seg. This patch: 1. Makes #pragma vtordisp use PragmaStack class as *_seg pragmas do; 2. Fixes "#pragma vtordisp()" behavior: it shouldn't affect stack; 3. Saves/restores the stacks on enter/exit a C++ method body. llvm-svn: 267866
This commit is contained in:
parent
5b4faeec87
commit
2008dbb4ed
|
@ -327,40 +327,21 @@ public:
|
|||
LangOptions::PragmaMSPointersToMembersKind
|
||||
MSPointerToMemberRepresentationMethod;
|
||||
|
||||
enum PragmaVtorDispKind {
|
||||
PVDK_Push, ///< #pragma vtordisp(push, mode)
|
||||
PVDK_Set, ///< #pragma vtordisp(mode)
|
||||
PVDK_Pop, ///< #pragma vtordisp(pop)
|
||||
PVDK_Reset ///< #pragma vtordisp()
|
||||
};
|
||||
|
||||
enum PragmaMsStackAction {
|
||||
PSK_Reset, // #pragma ()
|
||||
PSK_Set, // #pragma ("name")
|
||||
PSK_Push, // #pragma (push[, id])
|
||||
PSK_Push_Set, // #pragma (push[, id], "name")
|
||||
PSK_Pop, // #pragma (pop[, id])
|
||||
PSK_Pop_Set, // #pragma (pop[, id], "name")
|
||||
};
|
||||
|
||||
/// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft
|
||||
/// C++ ABI. Possible values are 0, 1, and 2, which mean:
|
||||
///
|
||||
/// 0: Suppress all vtordisps
|
||||
/// 1: Insert vtordisps in the presence of vbase overrides and non-trivial
|
||||
/// structors
|
||||
/// 2: Always insert vtordisps to support RTTI on partially constructed
|
||||
/// objects
|
||||
///
|
||||
/// The stack always has at least one element in it.
|
||||
SmallVector<MSVtorDispAttr::Mode, 2> VtorDispModeStack;
|
||||
|
||||
/// Stack of active SEH __finally scopes. Can be empty.
|
||||
SmallVector<Scope*, 2> CurrentSEHFinally;
|
||||
|
||||
/// \brief Source location for newly created implicit MSInheritanceAttrs
|
||||
SourceLocation ImplicitMSInheritanceAttrLoc;
|
||||
|
||||
enum PragmaMsStackAction {
|
||||
PSK_Reset = 0x0, // #pragma ()
|
||||
PSK_Set = 0x1, // #pragma (value)
|
||||
PSK_Push = 0x2, // #pragma (push[, id])
|
||||
PSK_Pop = 0x4, // #pragma (pop[, id])
|
||||
PSK_Push_Set = PSK_Push | PSK_Set, // #pragma (push[, id], value)
|
||||
PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value)
|
||||
};
|
||||
|
||||
template<typename ValueType>
|
||||
struct PragmaStack {
|
||||
struct Slot {
|
||||
|
@ -377,18 +358,84 @@ public:
|
|||
PragmaMsStackAction Action,
|
||||
llvm::StringRef StackSlotLabel,
|
||||
ValueType Value);
|
||||
explicit PragmaStack(const ValueType &Value)
|
||||
: CurrentValue(Value) {}
|
||||
|
||||
// MSVC seems to add artificial slots to #pragma stacks on entering a C++
|
||||
// method body to restore the stacks on exit, so it works like this:
|
||||
//
|
||||
// struct S {
|
||||
// #pragma <name>(push, InternalPragmaSlot, <current_pragma_value>)
|
||||
// void Method {}
|
||||
// #pragma <name>(pop, InternalPragmaSlot)
|
||||
// };
|
||||
//
|
||||
// It works even with #pragma vtordisp, although MSVC doesn't support
|
||||
// #pragma vtordisp(push [, id], n)
|
||||
// syntax.
|
||||
//
|
||||
// Push / pop a named sentinel slot.
|
||||
void SentinelAction(PragmaMsStackAction Action, StringRef Label) {
|
||||
assert((Action == PSK_Push || Action == PSK_Pop) &&
|
||||
"Can only push / pop #pragma stack sentinels!");
|
||||
Act(CurrentPragmaLocation, Action, Label, CurrentValue);
|
||||
}
|
||||
|
||||
// Constructors.
|
||||
explicit PragmaStack(const ValueType &Default)
|
||||
: DefaultValue(Default), CurrentValue(Default) {}
|
||||
|
||||
SmallVector<Slot, 2> Stack;
|
||||
ValueType DefaultValue; // Value used for PSK_Reset action.
|
||||
ValueType CurrentValue;
|
||||
SourceLocation CurrentPragmaLocation;
|
||||
};
|
||||
// FIXME: We should serialize / deserialize these if they occur in a PCH (but
|
||||
// we shouldn't do so if they're in a module).
|
||||
|
||||
/// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft
|
||||
/// C++ ABI. Possible values are 0, 1, and 2, which mean:
|
||||
///
|
||||
/// 0: Suppress all vtordisps
|
||||
/// 1: Insert vtordisps in the presence of vbase overrides and non-trivial
|
||||
/// structors
|
||||
/// 2: Always insert vtordisps to support RTTI on partially constructed
|
||||
/// objects
|
||||
PragmaStack<MSVtorDispAttr::Mode> VtorDispStack;
|
||||
PragmaStack<StringLiteral *> DataSegStack;
|
||||
PragmaStack<StringLiteral *> BSSSegStack;
|
||||
PragmaStack<StringLiteral *> ConstSegStack;
|
||||
PragmaStack<StringLiteral *> CodeSegStack;
|
||||
// TODO: Change implementation of #pragma pack to use PragmaStack<> approach.
|
||||
|
||||
// RAII object to psuh / pop sentinel slots for all MS #pragma stacks.
|
||||
// Actions should be performed only if we enter / exit a C++ method body.
|
||||
class PragmaStackSentinelRAII {
|
||||
public:
|
||||
PragmaStackSentinelRAII(Sema &S, StringRef SlotLabel, bool ShouldAct)
|
||||
: S(S), SlotLabel(SlotLabel), ShouldAct(ShouldAct) {
|
||||
if (ShouldAct) {
|
||||
S.VtorDispStack.SentinelAction(PSK_Push, SlotLabel);
|
||||
S.DataSegStack.SentinelAction(PSK_Push, SlotLabel);
|
||||
S.BSSSegStack.SentinelAction(PSK_Push, SlotLabel);
|
||||
S.ConstSegStack.SentinelAction(PSK_Push, SlotLabel);
|
||||
S.CodeSegStack.SentinelAction(PSK_Push, SlotLabel);
|
||||
}
|
||||
}
|
||||
|
||||
~PragmaStackSentinelRAII() {
|
||||
if (ShouldAct) {
|
||||
S.VtorDispStack.SentinelAction(PSK_Pop, SlotLabel);
|
||||
S.DataSegStack.SentinelAction(PSK_Pop, SlotLabel);
|
||||
S.BSSSegStack.SentinelAction(PSK_Pop, SlotLabel);
|
||||
S.ConstSegStack.SentinelAction(PSK_Pop, SlotLabel);
|
||||
S.CodeSegStack.SentinelAction(PSK_Pop, SlotLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Sema &S;
|
||||
StringRef SlotLabel;
|
||||
bool ShouldAct;
|
||||
};
|
||||
|
||||
/// A mapping that describes the nullability we've seen in each header file.
|
||||
FileNullabilityMap NullabilityMap;
|
||||
|
@ -1011,24 +1058,6 @@ public:
|
|||
bool OldFPContractState : 1;
|
||||
};
|
||||
|
||||
/// Records and restores the vtordisp state on entry/exit of C++ method body.
|
||||
class VtorDispStackRAII {
|
||||
public:
|
||||
VtorDispStackRAII(Sema &S, bool ShouldSaveAndRestore)
|
||||
: S(S), ShouldSaveAndRestore(ShouldSaveAndRestore), OldVtorDispStack() {
|
||||
if (ShouldSaveAndRestore)
|
||||
OldVtorDispStack = S.VtorDispModeStack;
|
||||
}
|
||||
~VtorDispStackRAII() {
|
||||
if (ShouldSaveAndRestore)
|
||||
S.VtorDispModeStack = OldVtorDispStack;
|
||||
}
|
||||
private:
|
||||
Sema &S;
|
||||
bool ShouldSaveAndRestore;
|
||||
SmallVector<MSVtorDispAttr::Mode, 2> OldVtorDispStack;
|
||||
};
|
||||
|
||||
void addImplicitTypedef(StringRef Name, QualType T);
|
||||
|
||||
public:
|
||||
|
@ -7666,7 +7695,8 @@ public:
|
|||
SourceLocation PragmaLoc);
|
||||
|
||||
/// \brief Called on well formed \#pragma vtordisp().
|
||||
void ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, SourceLocation PragmaLoc,
|
||||
void ActOnPragmaMSVtorDisp(PragmaMsStackAction Action,
|
||||
SourceLocation PragmaLoc,
|
||||
MSVtorDispAttr::Mode Value);
|
||||
|
||||
enum PragmaSectionKind {
|
||||
|
|
|
@ -497,11 +497,11 @@ void Parser::HandlePragmaMSPointersToMembers() {
|
|||
void Parser::HandlePragmaMSVtorDisp() {
|
||||
assert(Tok.is(tok::annot_pragma_ms_vtordisp));
|
||||
uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
|
||||
Sema::PragmaVtorDispKind Kind =
|
||||
static_cast<Sema::PragmaVtorDispKind>((Value >> 16) & 0xFFFF);
|
||||
Sema::PragmaMsStackAction Action =
|
||||
static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
|
||||
MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF);
|
||||
SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
|
||||
Actions.ActOnPragmaMSVtorDisp(Kind, PragmaLoc, Mode);
|
||||
Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode);
|
||||
}
|
||||
|
||||
void Parser::HandlePragmaMSPragma() {
|
||||
|
@ -1606,7 +1606,7 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
|
|||
}
|
||||
PP.Lex(Tok);
|
||||
|
||||
Sema::PragmaVtorDispKind Kind = Sema::PVDK_Set;
|
||||
Sema::PragmaMsStackAction Action = Sema::PSK_Set;
|
||||
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
if (II) {
|
||||
if (II->isStr("push")) {
|
||||
|
@ -1617,24 +1617,24 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
|
|||
return;
|
||||
}
|
||||
PP.Lex(Tok);
|
||||
Kind = Sema::PVDK_Push;
|
||||
Action = Sema::PSK_Push_Set;
|
||||
// not push, could be on/off
|
||||
} else if (II->isStr("pop")) {
|
||||
// #pragma vtordisp(pop)
|
||||
PP.Lex(Tok);
|
||||
Kind = Sema::PVDK_Pop;
|
||||
Action = Sema::PSK_Pop;
|
||||
}
|
||||
// not push or pop, could be on/off
|
||||
} else {
|
||||
if (Tok.is(tok::r_paren)) {
|
||||
// #pragma vtordisp()
|
||||
Kind = Sema::PVDK_Reset;
|
||||
Action = Sema::PSK_Reset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t Value = 0;
|
||||
if (Kind == Sema::PVDK_Push || Kind == Sema::PVDK_Set) {
|
||||
if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) {
|
||||
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
if (II && II->isStr("off")) {
|
||||
PP.Lex(Tok);
|
||||
|
@ -1676,7 +1676,7 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
|
|||
AnnotTok.setLocation(VtorDispLoc);
|
||||
AnnotTok.setAnnotationEndLoc(EndLoc);
|
||||
AnnotTok.setAnnotationValue(reinterpret_cast<void *>(
|
||||
static_cast<uintptr_t>((Kind << 16) | (Value & 0xFFFF))));
|
||||
static_cast<uintptr_t>((Action << 16) | (Value & 0xFFFF))));
|
||||
PP.EnterToken(AnnotTok);
|
||||
}
|
||||
|
||||
|
|
|
@ -1928,7 +1928,8 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
|
|||
// Save and reset current vtordisp stack if we have entered a C++ method body.
|
||||
bool IsCXXMethod =
|
||||
getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
|
||||
Sema::VtorDispStackRAII SavedVtorDispStack(Actions, IsCXXMethod);
|
||||
Sema::PragmaStackSentinelRAII
|
||||
PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod);
|
||||
|
||||
// Do not enter a scope for the brace, as the arguments are in the same scope
|
||||
// (the function body) as the body itself. Instead, just read the statement
|
||||
|
@ -1972,7 +1973,8 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
|
|||
// Save and reset current vtordisp stack if we have entered a C++ method body.
|
||||
bool IsCXXMethod =
|
||||
getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
|
||||
Sema::VtorDispStackRAII SavedVtorDispStack(Actions, IsCXXMethod);
|
||||
Sema::PragmaStackSentinelRAII
|
||||
PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod);
|
||||
|
||||
SourceLocation LBraceLoc = Tok.getLocation();
|
||||
StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true));
|
||||
|
|
|
@ -82,7 +82,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
|||
PackContext(nullptr), MSStructPragmaOn(false),
|
||||
MSPointerToMemberRepresentationMethod(
|
||||
LangOpts.getMSPointerToMemberRepresentationMethod()),
|
||||
VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
|
||||
VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
|
||||
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
|
||||
CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
|
||||
IsBuildingRecoveryCallExpr(false),
|
||||
|
|
|
@ -136,9 +136,9 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
|
|||
// FIXME: We should merge AddAlignmentAttributesForRecord with
|
||||
// AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes
|
||||
// all active pragmas and applies them as attributes to class definitions.
|
||||
if (VtorDispModeStack.back() != getLangOpts().VtorDispMode)
|
||||
if (VtorDispStack.CurrentValue != getLangOpts().VtorDispMode)
|
||||
RD->addAttr(
|
||||
MSVtorDispAttr::CreateImplicit(Context, VtorDispModeStack.back()));
|
||||
MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue));
|
||||
}
|
||||
|
||||
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
|
||||
|
@ -292,29 +292,13 @@ void Sema::ActOnPragmaMSPointersToMembers(
|
|||
ImplicitMSInheritanceAttrLoc = PragmaLoc;
|
||||
}
|
||||
|
||||
void Sema::ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind,
|
||||
void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action,
|
||||
SourceLocation PragmaLoc,
|
||||
MSVtorDispAttr::Mode Mode) {
|
||||
switch (Kind) {
|
||||
case PVDK_Set:
|
||||
VtorDispModeStack.back() = Mode;
|
||||
break;
|
||||
case PVDK_Push:
|
||||
VtorDispModeStack.push_back(Mode);
|
||||
break;
|
||||
case PVDK_Reset:
|
||||
VtorDispModeStack.clear();
|
||||
VtorDispModeStack.push_back(MSVtorDispAttr::Mode(LangOpts.VtorDispMode));
|
||||
break;
|
||||
case PVDK_Pop:
|
||||
VtorDispModeStack.pop_back();
|
||||
if (VtorDispModeStack.empty()) {
|
||||
Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp"
|
||||
<< "stack empty";
|
||||
VtorDispModeStack.push_back(MSVtorDispAttr::Mode(LangOpts.VtorDispMode));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (Action & PSK_Pop && VtorDispStack.Stack.empty())
|
||||
Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp"
|
||||
<< "stack empty";
|
||||
VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode);
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
|
@ -323,7 +307,7 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
|
|||
llvm::StringRef StackSlotLabel,
|
||||
ValueType Value) {
|
||||
if (Action == PSK_Reset) {
|
||||
CurrentValue = nullptr;
|
||||
CurrentValue = DefaultValue;
|
||||
return;
|
||||
}
|
||||
if (Action & PSK_Push)
|
||||
|
|
|
@ -31,6 +31,31 @@ int TEST1;
|
|||
#pragma bss_seg(pop)
|
||||
int TEST2;
|
||||
|
||||
|
||||
// Check "save-restore" of pragma stacks.
|
||||
struct Outer {
|
||||
void f() {
|
||||
#pragma bss_seg(push, ".bss3")
|
||||
#pragma code_seg(push, ".my_code1")
|
||||
#pragma const_seg(push, ".my_const1")
|
||||
#pragma data_seg(push, ".data3")
|
||||
struct Inner {
|
||||
void g() {
|
||||
#pragma bss_seg(push, ".bss4")
|
||||
#pragma code_seg(push, ".my_code2")
|
||||
#pragma const_seg(push, ".my_const2")
|
||||
#pragma data_seg(push, ".data4")
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
void h2(void) {} // should be in ".my_code"
|
||||
int TEST3; // should be in ".bss1"
|
||||
int d2 = 1; // should be in ".data"
|
||||
extern const int b2; // should be in ".my_const"
|
||||
const int b2 = 1;
|
||||
|
||||
#pragma section("read_flag_section", read)
|
||||
// Even though they are not declared const, these become constant since they are
|
||||
// in a read-only section.
|
||||
|
@ -63,6 +88,9 @@ __declspec(allocate("short_section")) short short_var = 42;
|
|||
//CHECK: @i = global i32 0
|
||||
//CHECK: @TEST1 = global i32 0
|
||||
//CHECK: @TEST2 = global i32 0, section ".bss1"
|
||||
//CHECK: @TEST3 = global i32 0, section ".bss1"
|
||||
//CHECK: @d2 = global i32 1, section ".data"
|
||||
//CHECK: @b2 = constant i32 1, section ".my_const"
|
||||
//CHECK: @unreferenced = constant i32 0, section "read_flag_section"
|
||||
//CHECK: @referenced = constant i32 42, section "read_flag_section"
|
||||
//CHECK: @implicitly_read_write = global i32 42, section "no_section_attributes"
|
||||
|
@ -70,3 +98,4 @@ __declspec(allocate("short_section")) short short_var = 42;
|
|||
//CHECK: @short_var = global i16 42, section "short_section"
|
||||
//CHECK: define void @g()
|
||||
//CHECK: define void @h() {{.*}} section ".my_code"
|
||||
//CHECK: define void @h2() {{.*}} section ".my_code"
|
||||
|
|
|
@ -22,7 +22,8 @@ struct B : virtual A { int b; };
|
|||
|
||||
// Test a reset.
|
||||
#pragma vtordisp()
|
||||
#pragma vtordisp(pop) // expected-warning {{#pragma vtordisp(pop, ...) failed: stack empty}}
|
||||
#pragma vtordisp(pop) // stack should NOT be affected by reset.
|
||||
// Now stack contains '1'.
|
||||
|
||||
#pragma vtordisp( // expected-warning {{unknown action for '#pragma vtordisp' - ignored}}
|
||||
#pragma vtordisp(asdf) // expected-warning {{unknown action for '#pragma vtordisp' - ignored}}
|
||||
|
@ -42,6 +43,7 @@ struct E {
|
|||
virtual void f();
|
||||
};
|
||||
|
||||
#pragma vtordisp(pop) // After this stack should be empty.
|
||||
#pragma vtordisp(pop) // expected-warning {{#pragma vtordisp(pop, ...) failed: stack empty}}
|
||||
|
||||
void g() {
|
||||
|
|
Loading…
Reference in New Issue