Skip to content

Commit 5bb99ed

Browse files
authored
[clang][Interp] Add inline descriptor to global variables (#72892)
Some time ago, I did a similar patch for local variables. Initializing global variables can fail as well: ```c++ constexpr int a = 1/0; static_assert(a == 0); ``` ... would succeed in the new interpreter, because we never saved the fact that `a` has not been successfully initialized.
1 parent f2816ff commit 5bb99ed

File tree

16 files changed

+200
-82
lines changed

16 files changed

+200
-82
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ bool ByteCodeExprGen<Emitter>::visitArrayElemInit(unsigned ElemIndex,
826826
return false;
827827
if (!this->visitInitializer(Init))
828828
return false;
829-
return this->emitPopPtr(Init);
829+
return this->emitInitPtrPop(Init);
830830
}
831831

832832
template <class Emitter>
@@ -854,13 +854,26 @@ bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
854854
return this->visitInitList(E->inits(), E);
855855

856856
if (T->isArrayType()) {
857-
// FIXME: Array fillers.
858857
unsigned ElementIndex = 0;
859858
for (const Expr *Init : E->inits()) {
860859
if (!this->visitArrayElemInit(ElementIndex, Init))
861860
return false;
862861
++ElementIndex;
863862
}
863+
864+
// Expand the filler expression.
865+
// FIXME: This should go away.
866+
if (const Expr *Filler = E->getArrayFiller()) {
867+
const ConstantArrayType *CAT =
868+
Ctx.getASTContext().getAsConstantArrayType(E->getType());
869+
uint64_t NumElems = CAT->getSize().getZExtValue();
870+
871+
for (; ElementIndex != NumElems; ++ElementIndex) {
872+
if (!this->visitArrayElemInit(ElementIndex, Filler))
873+
return false;
874+
}
875+
}
876+
864877
return true;
865878
}
866879

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
180180
if (!visitInitializer(Init))
181181
return false;
182182

183+
if (!this->emitInitPtr(Init))
184+
return false;
185+
183186
return this->emitPopPtr(Init);
184187
}
185188

@@ -191,6 +194,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
191194
if (!visitInitializer(Init))
192195
return false;
193196

197+
if (!this->emitInitPtr(Init))
198+
return false;
199+
194200
return this->emitPopPtr(Init);
195201
}
196202

@@ -202,7 +208,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
202208
if (!visitInitializer(I))
203209
return false;
204210

205-
return this->emitPopPtr(I);
211+
return this->emitInitPtrPop(I);
206212
}
207213

208214
bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *E);

clang/lib/AST/Interp/Descriptor.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -243,18 +243,19 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
243243
bool IsMutable)
244244
: Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
245245
MDSize(MD.value_or(0)),
246-
AllocSize(align(Size) + sizeof(InitMapPtr) + MDSize), IsConst(IsConst),
247-
IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true),
248-
CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
249-
MoveFn(getMoveArrayPrim(Type)) {
246+
AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)),
247+
IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
248+
IsArray(true), CtorFn(getCtorArrayPrim(Type)),
249+
DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
250250
assert(Source && "Missing source");
251251
}
252252

253253
/// Primitive unknown-size arrays.
254-
Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary,
255-
UnknownSize)
256-
: Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), MDSize(0),
257-
AllocSize(alignof(void *) + sizeof(InitMapPtr)), IsConst(true),
254+
Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
255+
bool IsTemporary, UnknownSize)
256+
: Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
257+
MDSize(MD.value_or(0)),
258+
AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), IsConst(true),
258259
IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
259260
CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
260261
MoveFn(getMoveArrayPrim(Type)) {
@@ -275,12 +276,12 @@ Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
275276
}
276277

277278
/// Unknown-size arrays of composite elements.
278-
Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem,
279+
Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
279280
bool IsTemporary, UnknownSize)
280281
: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
281-
Size(UnknownSizeMark), MDSize(0),
282-
AllocSize(alignof(void *) + sizeof(InitMapPtr)), ElemDesc(Elem),
283-
IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
282+
Size(UnknownSizeMark), MDSize(MD.value_or(0)),
283+
AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),
284+
IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
284285
CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
285286
assert(Source && "Missing source");
286287
}

clang/lib/AST/Interp/Descriptor.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ struct InlineDescriptor {
7373
unsigned IsFieldMutable : 1;
7474

7575
const Descriptor *Desc;
76+
77+
InlineDescriptor(const Descriptor *D)
78+
: Offset(sizeof(InlineDescriptor)), IsConst(false), IsInitialized(false),
79+
IsBase(false), IsActive(false), IsFieldMutable(false), Desc(D) {}
7680
};
7781

7882
/// Describes a memory block created by an allocation site.
@@ -128,15 +132,16 @@ struct Descriptor final {
128132
bool IsConst, bool IsTemporary, bool IsMutable);
129133

130134
/// Allocates a descriptor for an array of primitives of unknown size.
131-
Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary, UnknownSize);
135+
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MDSize,
136+
bool IsTemporary, UnknownSize);
132137

133138
/// Allocates a descriptor for an array of composites.
134139
Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
135140
unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable);
136141

137142
/// Allocates a descriptor for an array of composites of unknown size.
138-
Descriptor(const DeclTy &D, const Descriptor *Elem, bool IsTemporary,
139-
UnknownSize);
143+
Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
144+
bool IsTemporary, UnknownSize);
140145

141146
/// Allocates a descriptor for a record.
142147
Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst,

clang/lib/AST/Interp/Interp.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,23 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
356356
return false;
357357
}
358358

359+
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
360+
if (Ptr.isInitialized())
361+
return true;
362+
363+
assert(S.getLangOpts().CPlusPlus);
364+
const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());
365+
if ((!VD->hasConstantInitialization() &&
366+
VD->mightBeUsableInConstantExpressions(S.getCtx())) ||
367+
(S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&
368+
!VD->hasICEInitializer(S.getCtx()))) {
369+
const SourceInfo &Loc = S.Current->getSource(OpPC);
370+
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
371+
S.Note(VD->getLocation(), diag::note_declared_at);
372+
}
373+
return false;
374+
}
375+
359376
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
360377
if (!CheckLive(S, OpPC, Ptr, AK_Read))
361378
return false;

clang/lib/AST/Interp/Interp.h

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
8888

8989
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
9090
AccessKinds AK);
91+
/// Check if a global variable is initialized.
92+
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
9193

9294
/// Checks if a value can be stored in a block.
9395
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
@@ -1003,13 +1005,18 @@ bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
10031005

10041006
template <PrimType Name, class T = typename PrimConv<Name>::T>
10051007
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1006-
const Block *B = S.P.getGlobal(I);
1007-
1008-
if (!CheckConstant(S, OpPC, B->getDescriptor()))
1008+
const Pointer &Ptr = S.P.getPtrGlobal(I);
1009+
if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
10091010
return false;
1010-
if (B->isExtern())
1011+
if (Ptr.isExtern())
10111012
return false;
1012-
S.Stk.push<T>(B->deref<T>());
1013+
1014+
// If a global variable is uninitialized, that means the initializer we've
1015+
// compiled for it wasn't a constant expression. Diagnose that.
1016+
if (!CheckGlobalInitialized(S, OpPC, Ptr))
1017+
return false;
1018+
1019+
S.Stk.push<T>(Ptr.deref<T>());
10131020
return true;
10141021
}
10151022

@@ -1029,7 +1036,9 @@ bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
10291036

10301037
template <PrimType Name, class T = typename PrimConv<Name>::T>
10311038
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1032-
S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
1039+
const Pointer &P = S.P.getGlobal(I);
1040+
P.deref<T>() = S.Stk.pop<T>();
1041+
P.initialize();
10331042
return true;
10341043
}
10351044

@@ -1045,7 +1054,10 @@ bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
10451054
APValue *Cached = Temp->getOrCreateValue(true);
10461055
*Cached = APV;
10471056

1048-
S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
1057+
const Pointer &P = S.P.getGlobal(I);
1058+
P.deref<T>() = S.Stk.pop<T>();
1059+
P.initialize();
1060+
10491061
return true;
10501062
}
10511063

@@ -1267,6 +1279,12 @@ inline bool InitPtrPop(InterpState &S, CodePtr OpPC) {
12671279
return true;
12681280
}
12691281

1282+
inline bool InitPtr(InterpState &S, CodePtr OpPC) {
1283+
const Pointer &Ptr = S.Stk.peek<Pointer>();
1284+
Ptr.initialize();
1285+
return true;
1286+
}
1287+
12701288
inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
12711289
const Pointer &Ptr) {
12721290
Pointer Base = Ptr;
@@ -1323,7 +1341,7 @@ bool Store(InterpState &S, CodePtr OpPC) {
13231341
const Pointer &Ptr = S.Stk.peek<Pointer>();
13241342
if (!CheckStore(S, OpPC, Ptr))
13251343
return false;
1326-
if (!Ptr.isRoot())
1344+
if (Ptr.canBeInitialized())
13271345
Ptr.initialize();
13281346
Ptr.deref<T>() = Value;
13291347
return true;
@@ -1335,7 +1353,7 @@ bool StorePop(InterpState &S, CodePtr OpPC) {
13351353
const Pointer &Ptr = S.Stk.pop<Pointer>();
13361354
if (!CheckStore(S, OpPC, Ptr))
13371355
return false;
1338-
if (!Ptr.isRoot())
1356+
if (Ptr.canBeInitialized())
13391357
Ptr.initialize();
13401358
Ptr.deref<T>() = Value;
13411359
return true;
@@ -1347,7 +1365,7 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) {
13471365
const Pointer &Ptr = S.Stk.peek<Pointer>();
13481366
if (!CheckStore(S, OpPC, Ptr))
13491367
return false;
1350-
if (!Ptr.isRoot())
1368+
if (Ptr.canBeInitialized())
13511369
Ptr.initialize();
13521370
if (const auto *FD = Ptr.getField())
13531371
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
@@ -1362,7 +1380,7 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
13621380
const Pointer &Ptr = S.Stk.pop<Pointer>();
13631381
if (!CheckStore(S, OpPC, Ptr))
13641382
return false;
1365-
if (!Ptr.isRoot())
1383+
if (Ptr.canBeInitialized())
13661384
Ptr.initialize();
13671385
if (const auto *FD = Ptr.getField())
13681386
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));

clang/lib/AST/Interp/InterpFrame.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,7 @@ InterpFrame::InterpFrame(InterpState &S, const Function *Func,
3838
for (auto &Local : Scope.locals()) {
3939
Block *B = new (localBlock(Local.Offset)) Block(Local.Desc);
4040
B->invokeCtor();
41-
InlineDescriptor *ID = localInlineDesc(Local.Offset);
42-
ID->Desc = Local.Desc;
43-
ID->IsActive = true;
44-
ID->Offset = sizeof(InlineDescriptor);
45-
ID->IsBase = false;
46-
ID->IsFieldMutable = false;
47-
ID->IsConst = false;
48-
ID->IsInitialized = false;
41+
new (localInlineDesc(Local.Offset)) InlineDescriptor(Local.Desc);
4942
}
5043
}
5144
}
@@ -201,7 +194,7 @@ const FunctionDecl *InterpFrame::getCallee() const {
201194

202195
Pointer InterpFrame::getLocalPointer(unsigned Offset) const {
203196
assert(Offset < Func->getFrameSize() && "Invalid local offset.");
204-
return Pointer(localBlock(Offset), sizeof(InlineDescriptor));
197+
return Pointer(localBlock(Offset));
205198
}
206199

207200
Pointer InterpFrame::getParamPointer(unsigned Off) {

clang/lib/AST/Interp/Opcodes.td

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,8 @@ def GetPtrBasePop : Opcode {
317317
let Args = [ArgUint32];
318318
}
319319

320-
def InitPtrPop : Opcode {
321-
let Args = [];
322-
}
320+
def InitPtrPop : Opcode;
321+
def InitPtr : Opcode;
323322

324323
def GetPtrDerivedPop : Opcode {
325324
let Args = [ArgUint32];

clang/lib/AST/Interp/Pointer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
using namespace clang;
2020
using namespace clang::interp;
2121

22-
Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
22+
Pointer::Pointer(Block *Pointee)
23+
: Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
24+
Pointee->getDescriptor()->getMetadataSize()) {}
2325

2426
Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
2527
: Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}

0 commit comments

Comments
 (0)