Skip to content

Commit 9d6cec5

Browse files
authored
[clang][Interp] Fix activating via indirect field initializers (llvm#102753)
Pointer::activate() propagates up anyway, so that is handled. But we need to call activate() in any case since the parent might not be a union, but the activate() is still needed. Always call it and hope that the InUnion flag takes care of the potential performance problems.
1 parent 8d908b8 commit 9d6cec5

File tree

4 files changed

+47
-38
lines changed

4 files changed

+47
-38
lines changed

clang/lib/AST/Interp/Compiler.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4737,8 +4737,7 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
47374737
// Classify the return type.
47384738
ReturnType = this->classify(F->getReturnType());
47394739

4740-
auto emitFieldInitializer = [&](const Record *R, const Record::Field *F,
4741-
unsigned FieldOffset,
4740+
auto emitFieldInitializer = [&](const Record::Field *F, unsigned FieldOffset,
47424741
const Expr *InitExpr) -> bool {
47434742
// We don't know what to do with these, so just return false.
47444743
if (InitExpr->getType().isNull())
@@ -4750,8 +4749,6 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
47504749

47514750
if (F->isBitField())
47524751
return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr);
4753-
if (R->isUnion())
4754-
return this->emitInitThisFieldActive(*T, FieldOffset, InitExpr);
47554752
return this->emitInitThisField(*T, FieldOffset, InitExpr);
47564753
}
47574754
// Non-primitive case. Get a pointer to the field-to-initialize
@@ -4787,7 +4784,7 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
47874784
if (const FieldDecl *Member = Init->getMember()) {
47884785
const Record::Field *F = R->getField(Member);
47894786

4790-
if (!emitFieldInitializer(R, F, F->Offset, InitExpr))
4787+
if (!emitFieldInitializer(F, F->Offset, InitExpr))
47914788
return false;
47924789
} else if (const Type *Base = Init->getBaseClass()) {
47934790
const auto *BaseDecl = Base->getAsCXXRecordDecl();
@@ -4815,11 +4812,11 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
48154812
assert(IFD->getChainingSize() >= 2);
48164813

48174814
unsigned NestedFieldOffset = 0;
4818-
const Record *FieldRecord = nullptr;
48194815
const Record::Field *NestedField = nullptr;
48204816
for (const NamedDecl *ND : IFD->chain()) {
48214817
const auto *FD = cast<FieldDecl>(ND);
4822-
FieldRecord = this->P.getOrCreateRecord(FD->getParent());
4818+
const Record *FieldRecord =
4819+
this->P.getOrCreateRecord(FD->getParent());
48234820
assert(FieldRecord);
48244821

48254822
NestedField = FieldRecord->getField(FD);
@@ -4829,8 +4826,7 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
48294826
}
48304827
assert(NestedField);
48314828

4832-
if (!emitFieldInitializer(FieldRecord, NestedField, NestedFieldOffset,
4833-
InitExpr))
4829+
if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr))
48344830
return false;
48354831
} else {
48364832
assert(Init->isDelegatingInitializer());

clang/lib/AST/Interp/Interp.h

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,7 @@ bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
13911391
return false;
13921392
const Pointer &Field = This.atField(I);
13931393
Field.deref<T>() = S.Stk.pop<T>();
1394+
Field.activate();
13941395
Field.initialize();
13951396
return true;
13961397
}
@@ -1413,20 +1414,6 @@ bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
14131414
return true;
14141415
}
14151416

1416-
template <PrimType Name, class T = typename PrimConv<Name>::T>
1417-
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1418-
if (S.checkingPotentialConstantExpression())
1419-
return false;
1420-
const Pointer &This = S.Current->getThis();
1421-
if (!CheckThis(S, OpPC, This))
1422-
return false;
1423-
const Pointer &Field = This.atField(I);
1424-
Field.deref<T>() = S.Stk.pop<T>();
1425-
Field.activate();
1426-
Field.initialize();
1427-
return true;
1428-
}
1429-
14301417
/// 1) Pops the value from the stack
14311418
/// 2) Peeks a pointer from the stack
14321419
/// 3) Pushes the value to field I of the pointer on the stack
@@ -1451,17 +1438,6 @@ bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
14511438
return true;
14521439
}
14531440

1454-
template <PrimType Name, class T = typename PrimConv<Name>::T>
1455-
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1456-
const T &Value = S.Stk.pop<T>();
1457-
const Pointer &Ptr = S.Stk.pop<Pointer>();
1458-
const Pointer &Field = Ptr.atField(I);
1459-
Field.deref<T>() = Value;
1460-
Field.activate();
1461-
Field.initialize();
1462-
return true;
1463-
}
1464-
14651441
//===----------------------------------------------------------------------===//
14661442
// GetPtr Local/Param/Global/Field/This
14671443
//===----------------------------------------------------------------------===//

clang/lib/AST/Interp/Opcodes.td

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,6 @@ def SetThisField : AccessOpcode;
440440
// [Value] -> []
441441
def InitThisField : AccessOpcode;
442442
// [Value] -> []
443-
def InitThisFieldActive : AccessOpcode;
444-
// [Value] -> []
445443
def InitThisBitField : Opcode {
446444
let Types = [AluTypeClass];
447445
let Args = [ArgRecordField, ArgUint32];
@@ -451,8 +449,6 @@ def InitThisBitField : Opcode {
451449
def InitField : AccessOpcode;
452450
// [Pointer, Value] -> []
453451
def InitBitField : BitFieldOpcode;
454-
// [Pointer, Value] -> []
455-
def InitFieldActive : AccessOpcode;
456452

457453
//===----------------------------------------------------------------------===//
458454
// Pointer access

clang/test/AST/Interp/unions.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,45 @@ namespace Zeroing {
306306
static_assert(UnionWithUnnamedBitfield{}.n == 0, "");
307307
static_assert(UnionWithUnnamedBitfield{1}.n == 1, "");
308308
}
309+
310+
namespace IndirectField {
311+
struct S {
312+
struct {
313+
union {
314+
struct {
315+
int a;
316+
int b;
317+
};
318+
int c;
319+
};
320+
int d;
321+
};
322+
union {
323+
int e;
324+
int f;
325+
};
326+
constexpr S(int a, int b, int d, int e) : a(a), b(b), d(d), e(e) {}
327+
constexpr S(int c, int d, int f) : c(c), d(d), f(f) {}
328+
};
329+
330+
constexpr S s1(1,2,3,4);
331+
constexpr S s2(5, 6, 7);
332+
333+
static_assert(s1.a == 1, "");
334+
static_assert(s1.b == 2, "");
335+
336+
static_assert(s1.c == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
337+
static_assert(s1.d == 3, "");
338+
static_assert(s1.e == 4, "");
339+
static_assert(s1.f == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
340+
341+
static_assert(s2.a == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
342+
static_assert(s2.b == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
343+
static_assert(s2.c == 5, "");
344+
static_assert(s2.d == 6, "");
345+
static_assert(s2.e == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
346+
static_assert(s2.f == 7, "");
347+
}
348+
349+
309350
#endif

0 commit comments

Comments
 (0)