Skip to content

Commit 538bc1a

Browse files
committed
[clang][Interp] Add explicit dummy descriptors
Instead of (ab)using incomplete array types for this, add a 'Dummy' bit to Descriptor. We need to be able to differentiate between the two when adding an offset.
1 parent b22917e commit 538bc1a

File tree

8 files changed

+59
-15
lines changed

8 files changed

+59
-15
lines changed

clang/lib/AST/Interp/Descriptor.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,13 @@ Descriptor::Descriptor(const DeclTy &D, Record *R, MetadataSize MD,
284284
assert(Source && "Missing source");
285285
}
286286

287+
Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
288+
: Source(D), ElemSize(1), Size(ElemSize), MDSize(MD.value_or(0)),
289+
AllocSize(Size + MDSize), ElemRecord(nullptr), IsConst(true),
290+
IsMutable(false), IsTemporary(false), IsDummy(true) {
291+
assert(Source && "Missing source");
292+
}
293+
287294
QualType Descriptor::getType() const {
288295
if (auto *E = asExpr())
289296
return E->getType();

clang/lib/AST/Interp/Descriptor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ struct Descriptor final {
109109
const bool IsTemporary = false;
110110
/// Flag indicating if the block is an array.
111111
const bool IsArray = false;
112+
/// Flag indicating if this is a dummy descriptor.
113+
const bool IsDummy = false;
112114

113115
/// Storage management methods.
114116
const BlockCtorFn CtorFn = nullptr;
@@ -137,6 +139,8 @@ struct Descriptor final {
137139
Descriptor(const DeclTy &D, Record *R, MetadataSize MD, bool IsConst,
138140
bool IsTemporary, bool IsMutable);
139141

142+
Descriptor(const DeclTy &D, MetadataSize MD);
143+
140144
QualType getType() const;
141145
QualType getElemQualType() const;
142146
SourceLocation getLocation() const;
@@ -190,6 +194,8 @@ struct Descriptor final {
190194
bool isArray() const { return IsArray; }
191195
/// Checks if the descriptor is of a record.
192196
bool isRecord() const { return !IsArray && ElemRecord; }
197+
/// Checks if this is a dummy descriptor.
198+
bool isDummy() const { return IsDummy; }
193199
};
194200

195201
/// Bitfield tracking the initialisation status of elements of primitive arrays.

clang/lib/AST/Interp/Interp.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
186186
return true;
187187
}
188188

189+
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
190+
return !Ptr.isDummy();
191+
}
192+
189193
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
190194
CheckSubobjectKind CSK) {
191195
if (!Ptr.isZero())
@@ -268,6 +272,8 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
268272
}
269273

270274
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
275+
if (!CheckDummy(S, OpPC, Ptr))
276+
return false;
271277
if (!CheckLive(S, OpPC, Ptr, AK_Read))
272278
return false;
273279
if (!CheckExtern(S, OpPC, Ptr))

clang/lib/AST/Interp/Interp.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
5555
/// Checks if a pointer is live and accessible.
5656
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
5757
AccessKinds AK);
58+
59+
/// Checks if a pointer is a dummy pointer.
60+
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
61+
5862
/// Checks if a pointer is null.
5963
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
6064
CheckSubobjectKind CSK);
@@ -1423,8 +1427,9 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
14231427
// Compute the largest index into the array.
14241428
T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth());
14251429

1430+
bool Invalid = false;
14261431
// Helper to report an invalid offset, computed as APSInt.
1427-
auto InvalidOffset = [&]() {
1432+
auto DiagInvalidOffset = [&]() -> void {
14281433
const unsigned Bits = Offset.bitWidth();
14291434
APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
14301435
APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
@@ -1434,28 +1439,31 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
14341439
<< NewIndex
14351440
<< /*array*/ static_cast<int>(!Ptr.inArray())
14361441
<< static_cast<unsigned>(MaxIndex);
1437-
return false;
1442+
Invalid = true;
14381443
};
14391444

14401445
T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
14411446
if constexpr (Op == ArithOp::Add) {
14421447
// If the new offset would be negative, bail out.
14431448
if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1444-
return InvalidOffset();
1449+
DiagInvalidOffset();
14451450

14461451
// If the new offset would be out of bounds, bail out.
14471452
if (Offset.isPositive() && Offset > MaxOffset)
1448-
return InvalidOffset();
1453+
DiagInvalidOffset();
14491454
} else {
14501455
// If the new offset would be negative, bail out.
14511456
if (Offset.isPositive() && Index < Offset)
1452-
return InvalidOffset();
1457+
DiagInvalidOffset();
14531458

14541459
// If the new offset would be out of bounds, bail out.
14551460
if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1456-
return InvalidOffset();
1461+
DiagInvalidOffset();
14571462
}
14581463

1464+
if (Invalid && !Ptr.isDummy())
1465+
return false;
1466+
14591467
// Offset is valid - compute it on unsigned.
14601468
int64_t WideIndex = static_cast<int64_t>(Index);
14611469
int64_t WideOffset = static_cast<int64_t>(Offset);

clang/lib/AST/Interp/InterpBuiltin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
152152
if (!CheckLive(S, OpPC, StrPtr, AK_Read))
153153
return false;
154154

155+
if (!CheckDummy(S, OpPC, StrPtr))
156+
return false;
157+
155158
assert(StrPtr.getFieldDesc()->isPrimitiveArray());
156159

157160
size_t Len = 0;

clang/lib/AST/Interp/Pointer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ class Pointer {
313313
bool isActive() const { return Base == 0 || getInlineDesc()->IsActive; }
314314
/// Checks if a structure is a base class.
315315
bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
316+
/// Checks if the pointer pointers to a dummy value.
317+
bool isDummy() const { return getDeclDesc()->isDummy(); }
316318

317319
/// Checks if an object or a subfield is mutable.
318320
bool isConst() const {

clang/lib/AST/Interp/Program.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,16 +144,18 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *PD) {
144144
It != DummyParams.end())
145145
return It->second;
146146

147-
// Create a pointer to an incomplete array of the specified elements.
148-
QualType ElemTy = PD->getType();
149-
QualType Ty =
150-
Ctx.getASTContext().getIncompleteArrayType(ElemTy, ArrayType::Normal, 0);
147+
// Create dummy descriptor.
148+
Descriptor *Desc = allocateDescriptor(PD, std::nullopt);
149+
// Allocate a block for storage.
150+
unsigned I = Globals.size();
151151

152-
if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) {
153-
DummyParams[PD] = *Idx;
154-
return Idx;
155-
}
156-
return std::nullopt;
152+
auto *G = new (Allocator, Desc->getAllocSize())
153+
Global(getCurrentDecl(), Desc, /*IsStatic=*/true, /*IsExtern=*/false);
154+
G->block()->invokeCtor();
155+
156+
Globals.push_back(G);
157+
DummyParams[PD] = I;
158+
return I;
157159
}
158160

159161
std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,

clang/test/AST/Interp/c.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,13 @@ _Static_assert(&a != 0, ""); // ref-warning {{always true}} \
4747
// expected-warning {{always true}} \
4848
// pedantic-expected-warning {{always true}} \
4949
// pedantic-expected-warning {{is a GNU extension}}
50+
_Static_assert((&c + 1) != 0, ""); // pedantic-ref-warning {{is a GNU extension}} \
51+
// pedantic-expected-warning {{is a GNU extension}}
52+
_Static_assert((&a + 100) != 0, ""); // pedantic-ref-warning {{is a GNU extension}} \
53+
// pedantic-ref-note {{100 of non-array}} \
54+
// pedantic-expected-note {{100 of non-array}} \
55+
// pedantic-expected-warning {{is a GNU extension}}
56+
_Static_assert((&a - 100) != 0, ""); // pedantic-ref-warning {{is a GNU extension}} \
57+
// pedantic-expected-warning {{is a GNU extension}} \
58+
// pedantic-ref-note {{-100 of non-array}} \
59+
// pedantic-expected-note {{-100 of non-array}}

0 commit comments

Comments
 (0)