Skip to content

Commit 857ffa1

Browse files
authored
[clang][bytecode] Recursively start lifetimes as well (#141742)
The constructor starts the lifetime of all the subobjects.
1 parent 7fa3658 commit 857ffa1

File tree

3 files changed

+77
-10
lines changed

3 files changed

+77
-10
lines changed

clang/lib/AST/ByteCode/DynamicAllocator.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
8686
ID->IsInitialized = false;
8787
ID->IsVolatile = false;
8888

89-
ID->LifeState =
90-
AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started;
91-
;
89+
if (D->isCompositeArray())
90+
ID->LifeState = Lifetime::Started;
91+
else
92+
ID->LifeState =
93+
AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started;
9294

9395
B->IsDynamic = true;
9496

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,38 +1699,61 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
16991699
return Call(S, OpPC, F, VarArgSize);
17001700
}
17011701

1702+
static void startLifetimeRecurse(const Pointer &Ptr) {
1703+
if (const Record *R = Ptr.getRecord()) {
1704+
Ptr.startLifetime();
1705+
for (const Record::Field &Fi : R->fields())
1706+
startLifetimeRecurse(Ptr.atField(Fi.Offset));
1707+
return;
1708+
}
1709+
1710+
if (const Descriptor *FieldDesc = Ptr.getFieldDesc();
1711+
FieldDesc->isCompositeArray()) {
1712+
assert(Ptr.getLifetime() == Lifetime::Started);
1713+
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
1714+
startLifetimeRecurse(Ptr.atIndex(I).narrow());
1715+
return;
1716+
}
1717+
1718+
Ptr.startLifetime();
1719+
}
1720+
17021721
bool StartLifetime(InterpState &S, CodePtr OpPC) {
17031722
const auto &Ptr = S.Stk.peek<Pointer>();
17041723
if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
17051724
return false;
1706-
1707-
Ptr.startLifetime();
1725+
startLifetimeRecurse(Ptr.narrow());
17081726
return true;
17091727
}
17101728

17111729
// FIXME: It might be better to the recursing as part of the generated code for
17121730
// a destructor?
17131731
static void endLifetimeRecurse(const Pointer &Ptr) {
1714-
Ptr.endLifetime();
17151732
if (const Record *R = Ptr.getRecord()) {
1733+
Ptr.endLifetime();
17161734
for (const Record::Field &Fi : R->fields())
17171735
endLifetimeRecurse(Ptr.atField(Fi.Offset));
17181736
return;
17191737
}
17201738

17211739
if (const Descriptor *FieldDesc = Ptr.getFieldDesc();
17221740
FieldDesc->isCompositeArray()) {
1741+
// No endLifetime() for array roots.
1742+
assert(Ptr.getLifetime() == Lifetime::Started);
17231743
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
17241744
endLifetimeRecurse(Ptr.atIndex(I).narrow());
1745+
return;
17251746
}
1747+
1748+
Ptr.endLifetime();
17261749
}
17271750

17281751
/// Ends the lifetime of the peek'd pointer.
17291752
bool EndLifetime(InterpState &S, CodePtr OpPC) {
17301753
const auto &Ptr = S.Stk.peek<Pointer>();
17311754
if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
17321755
return false;
1733-
endLifetimeRecurse(Ptr);
1756+
endLifetimeRecurse(Ptr.narrow());
17341757
return true;
17351758
}
17361759

@@ -1739,7 +1762,7 @@ bool EndLifetimePop(InterpState &S, CodePtr OpPC) {
17391762
const auto &Ptr = S.Stk.pop<Pointer>();
17401763
if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
17411764
return false;
1742-
endLifetimeRecurse(Ptr);
1765+
endLifetimeRecurse(Ptr.narrow());
17431766
return true;
17441767
}
17451768

@@ -1758,9 +1781,9 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
17581781

17591782
// CheckLifetime for this and all base pointers.
17601783
for (Pointer P = Ptr;;) {
1761-
if (!CheckLifetime(S, OpPC, P, AK_Construct)) {
1784+
if (!CheckLifetime(S, OpPC, P, AK_Construct))
17621785
return false;
1763-
}
1786+
17641787
if (P.isRoot())
17651788
break;
17661789
P = P.getBase();

clang/test/AST/ByteCode/placement-new.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,3 +423,45 @@ namespace SubObj {
423423
}
424424
static_assert(construct_after_lifetime_2()); // both-error {{}} both-note {{in call}}
425425
}
426+
427+
namespace RecursiveLifetimeStart {
428+
struct B {
429+
int b;
430+
};
431+
432+
struct A {
433+
B b;
434+
int a;
435+
};
436+
437+
constexpr int foo() {
438+
A a;
439+
a.~A();
440+
441+
new (&a) A();
442+
a.a = 10;
443+
a.b.b = 12;
444+
return a.a;
445+
}
446+
static_assert(foo() == 10);
447+
}
448+
449+
namespace ArrayRoot {
450+
struct S {
451+
int a;
452+
};
453+
constexpr int foo() {
454+
S* ss = std::allocator<S>().allocate(2);
455+
new (ss) S{};
456+
new (ss + 1) S{};
457+
458+
S* ps = &ss[2];
459+
ps = ss;
460+
ps->~S();
461+
462+
std::allocator<S>().deallocate(ss);
463+
return 0;
464+
}
465+
466+
static_assert(foo() == 0);
467+
}

0 commit comments

Comments
 (0)