Skip to content

Commit eef5798

Browse files
committed
[clang][Interp] Create full type info for dummy pointers
1 parent 4cc9c6d commit eef5798

File tree

7 files changed

+36
-57
lines changed

7 files changed

+36
-57
lines changed

clang/lib/AST/Interp/Descriptor.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,14 +309,6 @@ Descriptor::Descriptor(const DeclTy &D)
309309
assert(Source && "Missing source");
310310
}
311311

312-
/// Dummy array.
313-
Descriptor::Descriptor(const DeclTy &D, UnknownSize)
314-
: Source(D), ElemSize(1), Size(UnknownSizeMark), MDSize(0),
315-
AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
316-
IsTemporary(false), IsArray(true), IsDummy(true) {
317-
assert(Source && "Missing source");
318-
}
319-
320312
QualType Descriptor::getType() const {
321313
if (auto *E = asExpr())
322314
return E->getType();

clang/lib/AST/Interp/Descriptor.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ struct Descriptor final {
125125
/// Flag indicating if the block is an array.
126126
const bool IsArray = false;
127127
/// Flag indicating if this is a dummy descriptor.
128-
const bool IsDummy = false;
128+
bool IsDummy = false;
129129

130130
/// Storage management methods.
131131
const BlockCtorFn CtorFn = nullptr;
@@ -159,8 +159,8 @@ struct Descriptor final {
159159
/// Allocates a dummy descriptor.
160160
Descriptor(const DeclTy &D);
161161

162-
/// Allocates a dummy array descriptor.
163-
Descriptor(const DeclTy &D, UnknownSize);
162+
/// Make this descriptor a dummy descriptor.
163+
void makeDummy() { IsDummy = true; }
164164

165165
QualType getType() const;
166166
QualType getElemQualType() const;

clang/lib/AST/Interp/Interp.h

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -823,9 +823,9 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
823823
// element in the same array are NOT equal. They have the same Base value,
824824
// but a different Offset. This is a pretty rare case, so we fix this here
825825
// by comparing pointers to the first elements.
826-
if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot())
826+
if (!LHS.isZero() && LHS.isArrayRoot())
827827
VL = LHS.atIndex(0).getByteOffset();
828-
if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot())
828+
if (!RHS.isZero() && RHS.isArrayRoot())
829829
VR = RHS.atIndex(0).getByteOffset();
830830

831831
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
@@ -1241,14 +1241,16 @@ inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
12411241
!CheckNull(S, OpPC, Ptr, CSK_Field))
12421242
return false;
12431243

1244-
if (CheckDummy(S, OpPC, Ptr)) {
1245-
if (!CheckExtern(S, OpPC, Ptr))
1246-
return false;
1247-
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1248-
return false;
1249-
if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1250-
return false;
1251-
}
1244+
if (!CheckExtern(S, OpPC, Ptr))
1245+
return false;
1246+
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1247+
return false;
1248+
if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1249+
return false;
1250+
1251+
if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1252+
return false;
1253+
12521254
S.Stk.push<Pointer>(Ptr.atField(Off));
12531255
return true;
12541256
}
@@ -1992,11 +1994,6 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
19921994
if (!Ptr.isZero()) {
19931995
if (!CheckArray(S, OpPC, Ptr))
19941996
return false;
1995-
1996-
if (Ptr.isDummy()) {
1997-
S.Stk.push<Pointer>(Ptr);
1998-
return true;
1999-
}
20001997
}
20011998

20021999
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
@@ -2013,11 +2010,6 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
20132010
if (!Ptr.isZero()) {
20142011
if (!CheckArray(S, OpPC, Ptr))
20152012
return false;
2016-
2017-
if (Ptr.isDummy()) {
2018-
S.Stk.push<Pointer>(Ptr);
2019-
return true;
2020-
}
20212013
}
20222014

20232015
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
@@ -2053,12 +2045,12 @@ inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
20532045
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
20542046
const Pointer &Ptr = S.Stk.pop<Pointer>();
20552047

2056-
if (Ptr.isZero() || Ptr.isDummy()) {
2048+
if (Ptr.isZero()) {
20572049
S.Stk.push<Pointer>(Ptr);
20582050
return true;
20592051
}
20602052

2061-
if (!Ptr.isUnknownSizeArray()) {
2053+
if (!Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
20622054
S.Stk.push<Pointer>(Ptr.atIndex(0));
20632055
return true;
20642056
}

clang/lib/AST/Interp/Pointer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,10 @@ APValue Pointer::toAPValue() const {
139139
else
140140
llvm_unreachable("Invalid allocation type");
141141

142-
if (isDummy() || isUnknownSizeArray() || Desc->asExpr())
142+
if (isDummy() || isUnknownSizeArray() || Desc->asExpr()) {
143143
return APValue(Base, CharUnits::Zero(), Path,
144144
/*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
145+
}
145146

146147
// TODO: compute the offset into the object.
147148
CharUnits Offset = CharUnits::Zero();

clang/lib/AST/Interp/Program.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,17 +148,20 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {
148148
if (auto It = DummyVariables.find(VD); It != DummyVariables.end())
149149
return It->second;
150150

151-
// Create dummy descriptor.
152-
// We create desriptors of 'array of unknown size' if the type is an array
153-
// type _and_ the size isn't known (it's not a ConstantArrayType). If the size
154-
// is known however, we create a regular dummy pointer.
155151
Descriptor *Desc;
156-
if (const auto *AT = VD->getType()->getAsArrayTypeUnsafe();
157-
AT && !isa<ConstantArrayType>(AT))
158-
Desc = allocateDescriptor(VD, Descriptor::UnknownSize{});
152+
if (std::optional<PrimType> T = Ctx.classify(VD->getType()))
153+
Desc = createDescriptor(VD, *T, std::nullopt, true, false);
159154
else
155+
Desc = createDescriptor(VD, VD->getType().getTypePtr(), std::nullopt, true,
156+
false);
157+
if (!Desc)
160158
Desc = allocateDescriptor(VD);
161159

160+
assert(Desc);
161+
Desc->makeDummy();
162+
163+
assert(Desc->isDummy());
164+
162165
// Allocate a block for storage.
163166
unsigned I = Globals.size();
164167

@@ -314,8 +317,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
314317
for (const FieldDecl *FD : RD->fields()) {
315318
// Note that we DO create fields and descriptors
316319
// for unnamed bitfields here, even though we later ignore
317-
// them everywhere. That's because so the FieldDecl's
318-
// getFieldIndex() matches.
320+
// them everywhere. That's so the FieldDecl's getFieldIndex() matches.
319321

320322
// Reserve space for the field's descriptor and the offset.
321323
BaseSize += align(sizeof(InlineDescriptor));
@@ -348,6 +350,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
348350
Descriptor::MetadataSize MDSize,
349351
bool IsConst, bool IsTemporary,
350352
bool IsMutable, const Expr *Init) {
353+
351354
// Classes and structures.
352355
if (const auto *RT = Ty->getAs<RecordType>()) {
353356
if (const auto *Record = getOrCreateRecord(RT->getDecl()))

clang/test/AST/Interp/builtin-align-cxx.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,6 @@
22
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 %s -fsyntax-only -verify=expected,both -fexperimental-new-constant-interpreter
33
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 %s -fsyntax-only -verify=ref,both
44

5-
6-
/// This is just a copy of the one from test/SemaCXX/ with some of the
7-
/// diagnostic output adapted.
8-
/// Also, align32array has an initializer now, which means it's not just
9-
/// a dummy pointer for us and we do actually have type information for it.
10-
/// In the future, we need to retain type information for dummy pointers as
11-
/// well, so here is a test that will break once we do that:
12-
namespace {
13-
_Alignas(32) char heh[4];
14-
static_assert(!__builtin_is_aligned(&heh[1], 4), ""); // expected-error {{failed}}
15-
}
16-
17-
185
// Check that we don't crash when using dependent types in __builtin_align:
196
template <typename a, a b>
207
void *c(void *d) { // both-note{{candidate template ignored}}
@@ -177,7 +164,7 @@ static_assert(wrap_align_up(static_cast<bool>(1), const_value(1 << 21)), ""); //
177164
// both-note@-1{{in instantiation of function template specialization 'wrap_align_up<bool>' requested here}}
178165

179166
// Check constant evaluation for pointers:
180-
_Alignas(32) char align32array[128] = {};
167+
_Alignas(32) char align32array[128];
181168
static_assert(&align32array[0] == &align32array[0], "");
182169
// __builtin_align_up/down can be constant evaluated as a no-op for values
183170
// that are known to have greater alignment:

clang/test/AST/Interp/c.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,7 @@ int Y __attribute__((annotate(
257257
42,
258258
(struct TestStruct) { .a = 1, .b = 2 }
259259
)));
260+
261+
/// This tests that we have full type info, even for values we cannot read.
262+
int dummyarray[5];
263+
_Static_assert(&dummyarray[0] < &dummyarray[1], ""); // pedantic-warning {{GNU extension}}

0 commit comments

Comments
 (0)