Skip to content

Commit d612d59

Browse files
committed
[clang][Interp] Fix local lvalue compound literals
Same fix we had for global ones: leave a pointer on the stack.
1 parent 55783bd commit d612d59

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,19 +1700,35 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr(
17001700
}
17011701

17021702
// Otherwise, use a local variable.
1703-
if (T) {
1703+
if (T && !E->isLValue()) {
17041704
// For primitive types, we just visit the initializer.
17051705
return this->delegate(Init);
17061706
} else {
1707-
if (std::optional<unsigned> LocalIndex = allocateLocal(Init)) {
1708-
if (!this->emitGetPtrLocal(*LocalIndex, E))
1707+
unsigned LocalIndex;
1708+
1709+
if (T)
1710+
LocalIndex = this->allocateLocalPrimitive(Init, *T, false, false);
1711+
else if (std::optional<unsigned> MaybeIndex = this->allocateLocal(Init))
1712+
LocalIndex = *MaybeIndex;
1713+
else
1714+
return false;
1715+
1716+
if (!this->emitGetPtrLocal(LocalIndex, E))
1717+
return false;
1718+
1719+
if (T) {
1720+
if (!this->visit(Init)) {
17091721
return false;
1722+
}
1723+
return this->emitInit(*T, E);
1724+
} else {
17101725
if (!this->visitInitializer(Init))
17111726
return false;
1712-
if (DiscardResult)
1713-
return this->emitPopPtr(E);
1714-
return true;
17151727
}
1728+
1729+
if (DiscardResult)
1730+
return this->emitPopPtr(E);
1731+
return true;
17161732
}
17171733

17181734
return false;

clang/lib/AST/Interp/Interp.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,19 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
13991399
return true;
14001400
}
14011401

1402+
template <PrimType Name, class T = typename PrimConv<Name>::T>
1403+
bool Init(InterpState &S, CodePtr OpPC) {
1404+
const T &Value = S.Stk.pop<T>();
1405+
const Pointer &Ptr = S.Stk.peek<Pointer>();
1406+
if (!CheckInit(S, OpPC, Ptr)) {
1407+
assert(false);
1408+
return false;
1409+
}
1410+
Ptr.initialize();
1411+
new (&Ptr.deref<T>()) T(Value);
1412+
return true;
1413+
}
1414+
14021415
template <PrimType Name, class T = typename PrimConv<Name>::T>
14031416
bool InitPop(InterpState &S, CodePtr OpPC) {
14041417
const T &Value = S.Stk.pop<T>();

clang/lib/AST/Interp/Opcodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ def StoreBitField : StoreBitFieldOpcode {}
476476
def StoreBitFieldPop : StoreBitFieldOpcode {}
477477

478478
// [Pointer, Value] -> []
479+
def Init : StoreOpcode {}
479480
def InitPop : StoreOpcode {}
480481
// [Pointer, Value] -> [Pointer]
481482
def InitElem : Opcode {

clang/test/AST/Interp/c.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,19 @@ void test4(void) {
180180
t1 = sizeof(int);
181181
}
182182

183+
void localCompoundLiteral(void) {
184+
struct S { int x, y; } s = {}; // pedantic-expected-warning {{use of an empty initializer}} \
185+
// pedantic-ref-warning {{use of an empty initializer}}
186+
struct T {
187+
int i;
188+
struct S s;
189+
} t1 = { 1, {} }; // pedantic-expected-warning {{use of an empty initializer}} \
190+
// pedantic-ref-warning {{use of an empty initializer}}
191+
192+
struct T t3 = {
193+
(int){}, // pedantic-expected-warning {{use of an empty initializer}} \
194+
// pedantic-ref-warning {{use of an empty initializer}}
195+
{} // pedantic-expected-warning {{use of an empty initializer}} \
196+
// pedantic-ref-warning {{use of an empty initializer}}
197+
};
198+
}

0 commit comments

Comments
 (0)