Skip to content

Commit 59e1366

Browse files
authored
[clang][Interp] Fix getField() for integral pointers (#102120)
Instead of just adding the Record::Field offset, instead get the FieldDecl offset in the RecordLayout. Unfortunately, the offset we pass to the ops here is not made to easily go back to a FieldDecl, so we have to iterate over the parent Record.
1 parent c3c2370 commit 59e1366

File tree

5 files changed

+49
-8
lines changed

5 files changed

+49
-8
lines changed

clang/lib/AST/Interp/Compiler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
335335
if (!PointeeType.isNull()) {
336336
if (std::optional<PrimType> T = classify(PointeeType))
337337
Desc = P.createDescriptor(SubExpr, *T);
338+
else
339+
Desc = P.createDescriptor(SubExpr, PointeeType.getTypePtr(),
340+
std::nullopt, true, false,
341+
/*IsMutable=*/false, nullptr);
338342
}
339343
return this->emitNull(classifyPrim(CE->getType()), Desc, CE);
340344
}

clang/lib/AST/Interp/Interp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,12 @@ inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
15041504

15051505
if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
15061506
return false;
1507+
1508+
if (Ptr.isIntegralPointer()) {
1509+
S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
1510+
return true;
1511+
}
1512+
15071513
S.Stk.push<Pointer>(Ptr.atField(Off));
15081514
return true;
15091515
}
@@ -1527,6 +1533,11 @@ inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
15271533
if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
15281534
return false;
15291535

1536+
if (Ptr.isIntegralPointer()) {
1537+
S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
1538+
return true;
1539+
}
1540+
15301541
S.Stk.push<Pointer>(Ptr.atField(Off));
15311542
return true;
15321543
}

clang/lib/AST/Interp/Pointer.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,30 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
597597
return std::nullopt;
598598
return Result;
599599
}
600+
601+
IntPointer IntPointer::atOffset(const ASTContext &ASTCtx,
602+
unsigned Offset) const {
603+
if (!this->Desc)
604+
return *this;
605+
const Record *R = this->Desc->ElemRecord;
606+
if (!R)
607+
return *this;
608+
609+
const Record::Field *F = nullptr;
610+
for (auto &It : R->fields()) {
611+
if (It.Offset == Offset) {
612+
F = &It;
613+
break;
614+
}
615+
}
616+
if (!F)
617+
return *this;
618+
619+
const FieldDecl *FD = F->Decl;
620+
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
621+
unsigned FieldIndex = FD->getFieldIndex();
622+
uint64_t FieldOffset =
623+
ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
624+
.getQuantity();
625+
return IntPointer{this->Desc, FieldOffset};
626+
}

clang/lib/AST/Interp/Pointer.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ struct BlockPointer {
4444
struct IntPointer {
4545
const Descriptor *Desc;
4646
uint64_t Value;
47+
48+
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const;
4749
};
4850

4951
enum class Storage { Block, Int, Fn };
@@ -88,6 +90,9 @@ class Pointer {
8890
PointeeStorage.Int.Value = 0;
8991
PointeeStorage.Int.Desc = nullptr;
9092
}
93+
Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) {
94+
PointeeStorage.Int = std::move(IntPtr);
95+
}
9196
Pointer(Block *B);
9297
Pointer(Block *B, uint64_t BaseAndOffset);
9398
Pointer(const Pointer &P);
@@ -161,9 +166,8 @@ class Pointer {
161166

162167
/// Creates a pointer to a field.
163168
[[nodiscard]] Pointer atField(unsigned Off) const {
169+
assert(isBlockPointer());
164170
unsigned Field = Offset + Off;
165-
if (isIntegralPointer())
166-
return Pointer(asIntPointer().Value + Field, asIntPointer().Desc);
167171
return Pointer(asBlockPointer().Pointee, Field, Field);
168172
}
169173

clang/test/AST/Interp/c.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ int somefunc(int i) {
101101
// all-warning {{overflow in expression; result is 131'073 with type 'int'}}
102102
}
103103

104-
/// FIXME: The following test is incorrect in the new interpreter.
105-
/// The null pointer returns 16 from its getIntegerRepresentation().
106104
#pragma clang diagnostic ignored "-Wpointer-to-int-cast"
107105
struct ArrayStruct {
108106
char n[1];
@@ -111,10 +109,7 @@ char name2[(int)&((struct ArrayStruct*)0)->n]; // expected-warning {{folded to c
111109
// pedantic-expected-warning {{folded to constant array}} \
112110
// ref-warning {{folded to constant array}} \
113111
// pedantic-ref-warning {{folded to constant array}}
114-
_Static_assert(sizeof(name2) == 0, ""); // expected-error {{failed}} \
115-
// expected-note {{evaluates to}} \
116-
// pedantic-expected-error {{failed}} \
117-
// pedantic-expected-note {{evaluates to}}
112+
_Static_assert(sizeof(name2) == 0, "");
118113

119114
#ifdef __SIZEOF_INT128__
120115
void *PR28739d = &(&PR28739d)[(__int128)(unsigned long)-1]; // all-warning {{refers past the last possible element}}

0 commit comments

Comments
 (0)