Skip to content

Commit d7f7093

Browse files
committed
ptr compare
1 parent aa31efc commit d7f7093

File tree

5 files changed

+87
-25
lines changed

5 files changed

+87
-25
lines changed

clang/lib/AST/ByteCode/Interp.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,8 +1095,9 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
10951095
}
10961096

10971097
if (Pointer::hasSameBase(LHS, RHS)) {
1098-
size_t A = LHS.computeOffsetForComparison();
1099-
size_t B = RHS.computeOffsetForComparison();
1098+
size_t A = LHS.computeOffsetForComparison(S.getASTContext());
1099+
size_t B = RHS.computeOffsetForComparison(S.getASTContext());
1100+
11001101
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(A, B))));
11011102
return true;
11021103
}

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,13 @@ void Pointer::print(llvm::raw_ostream &OS) const {
362362
}
363363
}
364364

365-
size_t Pointer::computeOffsetForComparison() const {
365+
/// Compute an offset that can be used to compare this pointer to another one
366+
/// with the same base. To get accurate results, we basically _have to_ compute
367+
/// the lvalue offset using the ASTRecordLayout.
368+
///
369+
/// FIXME: We're still mixing values from the record layout with our internal
370+
/// offsets, which will inevitably lead to cryptic errors.
371+
size_t Pointer::computeOffsetForComparison(const ASTContext &ASTCtx) const {
366372
switch (StorageKind) {
367373
case Storage::Int:
368374
return Int.Value + Offset;
@@ -378,7 +384,6 @@ size_t Pointer::computeOffsetForComparison() const {
378384
size_t Result = 0;
379385
Pointer P = *this;
380386
while (true) {
381-
382387
if (P.isVirtualBaseClass()) {
383388
Result += getInlineDesc()->Offset;
384389
P = P.getBase();
@@ -400,28 +405,29 @@ size_t Pointer::computeOffsetForComparison() const {
400405

401406
if (P.isRoot()) {
402407
if (P.isOnePastEnd())
403-
++Result;
408+
Result +=
409+
ASTCtx.getTypeSizeInChars(P.getDeclDesc()->getType()).getQuantity();
404410
break;
405411
}
406412

407-
if (const Record *R = P.getBase().getRecord(); R && R->isUnion()) {
408-
if (P.isOnePastEnd())
409-
++Result;
410-
// Direct child of a union - all have offset 0.
411-
P = P.getBase();
412-
continue;
413-
}
413+
assert(P.getField());
414+
const Record *R = P.getBase().getRecord();
415+
assert(R);
416+
417+
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
418+
Result += ASTCtx
419+
.toCharUnitsFromBits(
420+
Layout.getFieldOffset(P.getField()->getFieldIndex()))
421+
.getQuantity();
414422

415-
// Fields, etc.
416-
Result += P.getInlineDesc()->Offset;
417423
if (P.isOnePastEnd())
418-
++Result;
424+
Result +=
425+
ASTCtx.getTypeSizeInChars(P.getField()->getType()).getQuantity();
419426

420427
P = P.getBase();
421428
if (P.isRoot())
422429
break;
423430
}
424-
425431
return Result;
426432
}
427433

clang/lib/AST/ByteCode/Pointer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ class Pointer {
784784
/// Compute an integer that can be used to compare this pointer to
785785
/// another one. This is usually NOT the same as the pointer offset
786786
/// regarding the AST record layout.
787-
size_t computeOffsetForComparison() const;
787+
size_t computeOffsetForComparison(const ASTContext &ASTCtx) const;
788788

789789
private:
790790
friend class Block;

clang/lib/AST/ByteCode/Record.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,6 @@ class Record final {
6161
unsigned getSize() const { return BaseSize; }
6262
/// Returns the full size of the record, including records.
6363
unsigned getFullSize() const { return BaseSize + VirtualSize; }
64-
/// Returns a field.
65-
const Field *getField(const FieldDecl *FD) const;
66-
/// Returns a base descriptor.
67-
const Base *getBase(const RecordDecl *FD) const;
68-
/// Returns a base descriptor.
69-
const Base *getBase(QualType T) const;
70-
/// Returns a virtual base descriptor.
71-
const Base *getVirtualBase(const RecordDecl *RD) const;
7264
/// Returns the destructor of the record, if any.
7365
const CXXDestructorDecl *getDestructor() const {
7466
if (const auto *CXXDecl = dyn_cast<CXXRecordDecl>(Decl))
@@ -87,6 +79,8 @@ class Record final {
8779

8880
unsigned getNumFields() const { return Fields.size(); }
8981
const Field *getField(unsigned I) const { return &Fields[I]; }
82+
/// Returns a field.
83+
const Field *getField(const FieldDecl *FD) const;
9084

9185
using const_base_iter = BaseList::const_iterator;
9286
llvm::iterator_range<const_base_iter> bases() const {
@@ -98,6 +92,10 @@ class Record final {
9892
assert(I < getNumBases());
9993
return &Bases[I];
10094
}
95+
/// Returns a base descriptor.
96+
const Base *getBase(QualType T) const;
97+
/// Returns a base descriptor.
98+
const Base *getBase(const RecordDecl *FD) const;
10199

102100
using const_virtual_iter = VirtualBaseList::const_iterator;
103101
llvm::iterator_range<const_virtual_iter> virtual_bases() const {
@@ -106,6 +104,8 @@ class Record final {
106104

107105
unsigned getNumVirtualBases() const { return VirtualBases.size(); }
108106
const Base *getVirtualBase(unsigned I) const { return &VirtualBases[I]; }
107+
/// Returns a virtual base descriptor.
108+
const Base *getVirtualBase(const RecordDecl *RD) const;
109109

110110
void dump(llvm::raw_ostream &OS, unsigned Indentation = 0,
111111
unsigned Offset = 0) const;

clang/test/AST/ByteCode/cxx20.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,3 +1225,58 @@ namespace ConditionalTemporaries {
12251225
static_assert(foo(false)== 13);
12261226
static_assert(foo(true)== 12);
12271227
}
1228+
1229+
namespace PointerCmp {
1230+
struct K {
1231+
struct {
1232+
long a;
1233+
alignas(8) int b;
1234+
} m;
1235+
char c;
1236+
};
1237+
constexpr K k{1,2, 3};
1238+
static_assert((void*)(&k.m.a + 1) == (void*)&k.m.b);
1239+
static_assert((void*)(&k.m + 1) == (void*)&k.c);
1240+
static_assert((void*)(&k + 1) != (void*)(&k.c + 1));
1241+
1242+
struct K2 {
1243+
struct {
1244+
int a;
1245+
alignas(8) int b;
1246+
} m;
1247+
long c;
1248+
};
1249+
constexpr K2 k2{1,2, 3};
1250+
static_assert((void*)(&k2.m.a + 1) != (void*)&k2.m.b);
1251+
/// static_assert((void*)(&k2.m.a + 1) < (void*)&k2.m.b); FIXME
1252+
static_assert((void*)(&k2.m + 1) == (void*)&k2.c);
1253+
static_assert((void*)(&k2 + 1) == (void*)(&k2.c + 1));
1254+
1255+
1256+
struct tuple {
1257+
int a;
1258+
int b;
1259+
};
1260+
1261+
constexpr tuple tpl{1,2};
1262+
static_assert((void*)&tpl == (void*)&tpl.a);
1263+
1264+
1265+
struct B {
1266+
int a;
1267+
};
1268+
1269+
struct tuple2 : public B {
1270+
int b;
1271+
};
1272+
constexpr tuple2 tpl2{1,2};
1273+
static_assert((void*)&tpl2 == (void*)&tpl2.a);
1274+
1275+
struct A {
1276+
int i[3];
1277+
long c;
1278+
};
1279+
constexpr A a{1,2, 3};
1280+
static_assert((void*)(&a.i + 1) != (void*)(&a.i[1])); // expected-error {{static assertion failed}}
1281+
static_assert((void*)(&a.i[2] + 1) == (void*)(&a.i[3]));
1282+
}

0 commit comments

Comments
 (0)