Skip to content

Commit ea3eb8d

Browse files
authored
[clang][bytecode] Fix bos/bdos with non-zero offset applied (#136482)
Compute the offset from the record layout. Unfortunately, not all the test cases from the current interpreter work.
1 parent 839f521 commit ea3eb8d

File tree

2 files changed

+91
-2
lines changed

2 files changed

+91
-2
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2196,6 +2196,53 @@ static unsigned computeFullDescSize(const ASTContext &ASTCtx,
21962196
return 0;
21972197
}
21982198

2199+
static unsigned computePointerOffset(const ASTContext &ASTCtx,
2200+
const Pointer &Ptr) {
2201+
unsigned Result = 0;
2202+
2203+
Pointer P = Ptr;
2204+
while (P.isArrayElement() || P.isField()) {
2205+
P = P.expand();
2206+
const Descriptor *D = P.getFieldDesc();
2207+
2208+
if (P.isArrayElement()) {
2209+
unsigned ElemSize =
2210+
ASTCtx.getTypeSizeInChars(D->getElemQualType()).getQuantity();
2211+
if (P.isOnePastEnd())
2212+
Result += ElemSize * P.getNumElems();
2213+
else
2214+
Result += ElemSize * P.getIndex();
2215+
P = P.expand().getArray();
2216+
} else if (P.isBaseClass()) {
2217+
2218+
const auto *RD = cast<CXXRecordDecl>(D->asDecl());
2219+
bool IsVirtual = Ptr.isVirtualBaseClass();
2220+
P = P.getBase();
2221+
const Record *BaseRecord = P.getRecord();
2222+
2223+
const ASTRecordLayout &Layout =
2224+
ASTCtx.getASTRecordLayout(cast<CXXRecordDecl>(BaseRecord->getDecl()));
2225+
if (IsVirtual)
2226+
Result += Layout.getVBaseClassOffset(RD).getQuantity();
2227+
else
2228+
Result += Layout.getBaseClassOffset(RD).getQuantity();
2229+
} else if (P.isField()) {
2230+
const FieldDecl *FD = P.getField();
2231+
const ASTRecordLayout &Layout =
2232+
ASTCtx.getASTRecordLayout(FD->getParent());
2233+
unsigned FieldIndex = FD->getFieldIndex();
2234+
uint64_t FieldOffset =
2235+
ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
2236+
.getQuantity();
2237+
Result += FieldOffset;
2238+
P = P.getBase();
2239+
} else
2240+
llvm_unreachable("Unhandled descriptor type");
2241+
}
2242+
2243+
return Result;
2244+
}
2245+
21992246
static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC,
22002247
const InterpFrame *Frame,
22012248
const Function *Func,
@@ -2217,7 +2264,7 @@ static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC,
22172264

22182265
const ASTContext &ASTCtx = S.getASTContext();
22192266

2220-
unsigned ByteOffset = 0;
2267+
unsigned ByteOffset = computePointerOffset(ASTCtx, Ptr);
22212268
unsigned FullSize = computeFullDescSize(ASTCtx, DeclDesc);
22222269

22232270
pushInteger(S, FullSize - ByteOffset, Call->getType());

clang/test/AST/ByteCode/builtin-object-size.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected %s
22
// RUN: %clang_cc1 -verify=both,ref %s
33

4-
// both-no-diagnostics
4+
// ref-no-diagnostics
5+
6+
typedef __SIZE_TYPE__ size_t;
57

68
int a;
79
static_assert(__builtin_object_size(&a, 0) == sizeof(int), "");
@@ -12,3 +14,43 @@ static_assert(__builtin_object_size(&arr, 0) == (sizeof(int)*2), "");
1214

1315
float arrf[2];
1416
static_assert(__builtin_object_size(&arrf, 0) == (sizeof(float)*2), "");
17+
static_assert(__builtin_object_size(&arrf[1], 0) == sizeof(float), "");
18+
static_assert(__builtin_object_size(&arrf[2], 0) == 0, "");
19+
20+
21+
22+
struct S {
23+
int a;
24+
char c;
25+
};
26+
27+
S s;
28+
static_assert(__builtin_object_size(&s, 0) == sizeof(s), "");
29+
30+
S ss[2];
31+
static_assert(__builtin_object_size(&ss[1], 0) == sizeof(s), "");
32+
static_assert(__builtin_object_size(&ss[1].c, 0) == sizeof(int), "");
33+
34+
struct A { char buf[16]; };
35+
struct B : A {};
36+
struct C { int i; B bs[1]; } c;
37+
static_assert(__builtin_object_size(&c.bs[0], 3) == 16);
38+
static_assert(__builtin_object_size(&c.bs[1], 3) == 0);
39+
40+
/// These are from test/SemaCXX/builtin-object-size-cxx14.
41+
/// They all don't work since they are rejected when evaluating the first
42+
/// parameter of the __builtin_object_size call.
43+
///
44+
/// GCC rejects them as well.
45+
namespace InvalidBase {
46+
// Ensure this doesn't crash.
47+
struct S { const char *name; };
48+
S invalid_base(); // expected-note {{declared here}}
49+
constexpr size_t bos_name = __builtin_object_size(invalid_base().name, 1); // expected-error {{must be initialized by a constant expression}} \
50+
// expected-note {{non-constexpr function 'invalid_base'}}
51+
52+
struct T { ~T(); };
53+
T invalid_base_2();
54+
constexpr size_t bos_dtor = __builtin_object_size(&(T&)(T&&)invalid_base_2(), 0); // expected-error {{must be initialized by a constant expression}} \
55+
// expected-note {{non-literal type 'T'}}
56+
}

0 commit comments

Comments
 (0)