clang 24.0.0git
InterpBuiltinObjectSize.cpp
Go to the documentation of this file.
1//===------------- InterpBuiltinObjectSize.cpp ------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// Implementation of the frontend part of the __builtin_object_size and
10// __builtin_dynamic_object_size builtins.
11
12#include "InterpHelpers.h"
13#include "Pointer.h"
14#include "Record.h"
16
17using namespace clang;
18using namespace clang::interp;
19
20enum : uint8_t {
21 Regular = 1 << 0,
24};
25
26// Helper to check if a Type can be passed to
27// ASTContext::getRecordLayout().
28static bool validType(QualType T) {
29 if (const RecordDecl *RD = T->getAsRecordDecl())
30 return ASTContext::hasLayout(RD);
31 return true;
32}
33
35 const OpaquePointer &OP,
36 unsigned TypeModifier = 0) {
37 QualType CurType = OP.getObjectType();
38
39 unsigned Drop = 0;
40 if (TypeModifier & IgnoreBaseCasts && OP.PathLength != 0 &&
41 OP.path().back().Kind == PointerPathEntry::Base)
42 Drop = 1;
43
44 if (TypeModifier & SurroundingArray && OP.PathLength != 0 &&
45 OP.path().back().Kind == PointerPathEntry::Array)
46 Drop = 1;
47
48 for (const PointerPathEntry &Entry : OP.path().drop_back(Drop)) {
49 switch (Entry.Kind) {
51 CurType = ASTCtx.getCanonicalTagType(Entry.RD.getPointer());
52 break;
54 CurType = Entry.FD->getType();
55 break;
58 if (!CurType->isArrayType())
59 continue;
60 CurType = CurType->getAsArrayTypeUnsafe()->getElementType();
61 }
62 }
63
64 return CurType;
65}
66
67static std::optional<unsigned> computeFullDescSize(const ASTContext &ASTCtx,
68 const Descriptor *Desc) {
69 if (Desc->isPrimitive() || Desc->isArray()) {
70 QualType T = Desc->getType();
71 if (!validType(T))
72 return std::nullopt;
73 return ASTCtx.getTypeSizeInChars(T).getQuantity();
74 }
75
76 if (Desc->isRecord()) {
77 // Can't use Descriptor::getType() as that may return a pointer type. Look
78 // at the decl directly.
79
80 const RecordDecl *RD = Desc->ElemRecord->getDecl();
81 if (!ASTContext::hasLayout(RD))
82 return std::nullopt;
83
84 return ASTCtx.getTypeSizeInChars(ASTCtx.getCanonicalTagType(RD))
85 .getQuantity();
86 }
87
88 return std::nullopt;
89}
90
91/// Compute the byte offset of \p Ptr in the full declaration.
92static unsigned computePointerOffset(const ASTContext &ASTCtx,
93 const Pointer &Ptr) {
94 return Ptr.computeLayoutOffset(ASTCtx).value_or(0);
95}
96
97/// Does Ptr point to the last subobject?
98static bool pointsToLastObject(const Pointer &Ptr) {
99 Pointer P = Ptr;
100 while (!P.isRoot()) {
101
102 if (P.isArrayElement()) {
103 P = P.expand().getArray();
104 continue;
105 }
106 if (P.isBaseClass()) {
107 if (P.getRecord()->getNumFields() > 0)
108 return false;
109 P = P.getBase();
110 continue;
111 }
112
113 Pointer Base = P.getBase();
114 if (const Record *R = Base.getRecord()) {
115 assert(P.getField());
116 if (P.getField()->getFieldIndex() != R->getNumFields() - 1)
117 return false;
118 }
119 P = Base;
120 }
121
122 return true;
123}
124
125/// Does Ptr point to the last object AND to a flexible array member?
126static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const Pointer &Ptr,
127 bool InvalidBase) {
128 auto isFlexibleArrayMember = [&](const Descriptor *FieldDesc) {
130 FAMKind StrictFlexArraysLevel =
131 Ctx.getLangOpts().getStrictFlexArraysLevel();
132
133 if (StrictFlexArraysLevel == FAMKind::Default)
134 return true;
135
136 unsigned NumElems = FieldDesc->getNumElems();
137 if (NumElems == 0 && StrictFlexArraysLevel != FAMKind::IncompleteOnly)
138 return true;
139
140 if (NumElems == 1 && StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
141 return true;
142 return false;
143 };
144
145 const Descriptor *FieldDesc = Ptr.getFieldDesc();
146 if (!FieldDesc->isArray())
147 return false;
148
149 return InvalidBase && pointsToLastObject(Ptr) &&
150 isFlexibleArrayMember(FieldDesc);
151}
152
153static bool isUserWritingOffTheEnd(const ASTContext &ASTCtx,
154 const OpaquePointer &OP) {
155 if (OP.PathLength == 0)
156 return false;
157
158 QualType CurType = OP.getObjectType();
159 for (unsigned I = 0; I != OP.PathLength; ++I) {
160 const PointerPathEntry &Entry = OP.Path[I];
161 switch (Entry.Kind) {
163 return false;
165 const FieldDecl *FD = OP.Path[I].FD;
166 if (!FD->getParent()->isUnion() &&
167 FD->getFieldIndex() != FD->getParent()->getNumFields() - 1)
168 return false;
169 CurType = FD->getType();
170 } break;
172 if (I == OP.PathLength - 1)
173 break;
174
175 if (!CurType->isArrayType())
176 break;
177
178 unsigned Index = OP.Path[I].Index;
179 const ArrayType *AT = CurType->getAsArrayTypeUnsafe();
180 assert(AT);
181 if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
182 if (Index != CAT->getLimitedSize() - 1)
183 return false;
184 CurType = CAT->getElementType();
185 } else {
186 return false;
187 }
188 } break;
190 return false;
191 }
192 }
193
194 // We're pointing to the last field in the full object.
195 // CurType is now the most derived type.
196 if (!CurType->isArrayType())
197 return false;
198
199 if (isa<IncompleteArrayType>(CurType))
200 return true;
201
202 const auto *CAT = dyn_cast<ConstantArrayType>(CurType);
203 if (!CAT)
204 return false;
205
207 FAMKind StrictFlexArraysLevel =
208 ASTCtx.getLangOpts().getStrictFlexArraysLevel();
209
210 if (StrictFlexArraysLevel == FAMKind::Default)
211 return true;
212
213 unsigned Size = CAT->getZExtSize();
214 if (Size == 0 && StrictFlexArraysLevel != FAMKind::IncompleteOnly)
215 return true;
216
217 if (Size == 1 && StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
218 return true;
219 return false;
220}
221
222/// Determine the offset of the given pointer. Depending on \c
223/// UseClosestSurroundingVariable, the offset is either relative to the full
224/// object or to the closest surrounding field or array.
225static std::optional<uint64_t>
226computeOpaquePtrOffset(const ASTContext &ASTCtx, const Pointer &Ptr,
227 bool UseClosestSurroundingVariable,
228 bool &OffsetIsNegative) {
229 const OpaquePointer &OP = Ptr.asOpaquePointer();
230
231 uint64_t Offset = 0;
232 std::optional<uint64_t> SurroundingArrayOffset;
233 QualType CurType = OP.getObjectType();
234 for (const PointerPathEntry &Entry : OP.path()) {
235 switch (Entry.Kind) {
237 const RecordDecl *RD = CurType->getAsRecordDecl();
238 if (!ASTContext::hasLayout(RD))
239 return std::nullopt;
240
241 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
242 Offset += Layout.getBaseClassOffset(Entry.RD.getPointer()).getQuantity();
243
244 CurType = ASTCtx.getCanonicalTagType(Entry.RD.getPointer());
245 } break;
246
248 const FieldDecl *FD = Entry.FD;
249 const RecordDecl *RD = FD->getParent();
250 if (!ASTContext::hasLayout(RD))
251 return std::nullopt;
252
253 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
254 Offset +=
256 .getQuantity();
257
258 CurType = FD->getType();
259 } break;
262 bool Add = (Entry.Kind == PointerPathEntry::Array);
263 uint64_t Index = Entry.Index;
264 if (!Add) {
265 // NegativeArray is always > 0.
266 OffsetIsNegative = true;
267 }
268 SurroundingArrayOffset = Offset;
269 if (!CurType->isArrayType()) {
270 if (Add)
271 Offset += Index * ASTCtx.getTypeSizeInChars(CurType).getQuantity();
272 else
273 Offset -= Index * ASTCtx.getTypeSizeInChars(CurType).getQuantity();
274 continue;
275 }
276 const ArrayType *AT = CurType->getAsArrayTypeUnsafe();
277 assert(AT);
278 QualType ElemTy = AT->getElementType();
279 if (!validType(ElemTy) || isa<VariableArrayType>(AT))
280 return std::nullopt;
281 if (Add)
282 Offset += Index * ASTCtx.getTypeSizeInChars(ElemTy).getQuantity();
283 else
284 Offset -= Index * ASTCtx.getTypeSizeInChars(ElemTy).getQuantity();
285 CurType = AT->getElementType();
286 } break;
287 }
288 }
289
290 if (UseClosestSurroundingVariable && SurroundingArrayOffset)
291 return Offset - *SurroundingArrayOffset;
292
293 QualType Ty = CurType.getNonReferenceType();
294
295 if (UseClosestSurroundingVariable &&
296 (Ty->isIncompleteType() || Ty->isFunctionType()))
297 return std::nullopt;
298
300 return std::nullopt;
301
302 if (OP.PathLength == 1 && OP.path().back().Kind == PointerPathEntry::Field &&
303 isa<IncompleteArrayType>(CurType)) {
304 return Offset;
305 }
306
307 if (UseClosestSurroundingVariable)
308 return 0;
309
310 return Offset;
311}
312
313/// Check if the given pointer points to the complete object, i.e. either to the
314/// very beginning or after the end (into the flexible array member) of the
315/// object.
316static bool pointsToCompleteObject(const ASTContext &ASTCtx,
317 const Pointer &Ptr) {
318 const OpaquePointer &OP = Ptr.asOpaquePointer();
319 if (OP.PathLength == 0)
320 return true;
321
322 QualType FieldType = computeFieldType(ASTCtx, OP);
323 if (OP.isArrayElement())
324 FieldType = OP.getSurroundingArray();
325 return isa<IncompleteArrayType>(FieldType);
326}
327
328static std::optional<unsigned>
329computeOpaqueSize(const ASTContext &ASTCtx, const Pointer &Ptr,
330 bool UseClosestSurroundingVariable, bool WritingOffTheEnd,
331 bool DetermineForCompleteObject) {
332 const OpaquePointer &OP = Ptr.asOpaquePointer();
333
334 CharUnits TypeSize;
335 // NOTE: Clang does not consider base casts. GCC does.
336 if (UseClosestSurroundingVariable) {
337 QualType FieldTy =
339 if (!validType(FieldTy))
340 return std::nullopt;
341 TypeSize = ASTCtx.getTypeSizeInChars(FieldTy);
342 } else {
343 QualType ObjectTy = OP.getObjectType();
344 if (!validType(ObjectTy))
345 return std::nullopt;
346 TypeSize = ASTCtx.getTypeSizeInChars(ObjectTy);
347 }
348
349 // The Flexible array member should only be checked if we're pointing to the
350 // object as a whole, or if we're looking for the whole object size.
351 if (!WritingOffTheEnd && !DetermineForCompleteObject)
352 return TypeSize.getQuantity();
353
354 // Check if we need to add the flexible array member size.
355 const VarDecl *Base = dyn_cast<VarDecl>(OP.Base);
356 if (!Base)
357 return TypeSize.getQuantity();
358
359 // If the base type is an incomplete array type (not a flexible array member
360 // of a struct), and we're looking for the complete object... we can't.
361 if (DetermineForCompleteObject && isa<IncompleteArrayType>(Base->getType()))
362 return std::nullopt;
363
364 if (!Base->getType()->isRecordType())
365 return TypeSize.getQuantity();
366
367 if (!Base->hasInit())
368 return TypeSize.getQuantity();
369 CharUnits FlexibleArraySize = Base->getFlexibleArrayInitChars(ASTCtx);
370 return (TypeSize + FlexibleArraySize).getQuantity();
371}
372
373namespace clang {
374namespace interp {
375
376/// Evaluate __builtin_object_size or __builtin_dynamic_object_size for the
377/// given pointer and Kind.
378///
379/// When computing the final result, the most important variable is
380/// UseClosestSurroundingVariable. If it is true, we will use the field the
381/// pointer points to, or the parent array of the element.
382/// UseClosestSurroundingVariable is true for Kind 1 and 3.
384 unsigned Kind, Pointer &Ptr,
385 const Expr *E, bool IsDynamic) {
386 if (Ptr.isZero())
387 return std::nullopt;
388
389 bool InvalidBase = false;
390 if (Ptr.isOpaquePointer()) {
391 bool UseClosestSurroundingVariable = (Kind == 1) || (Kind == 3);
392 const OpaquePointer &OP = Ptr.asOpaquePointer();
393 InvalidBase = OP.Base->getType()->isPointerType();
394 bool DetermineForCompleteObject = pointsToCompleteObject(ASTCtx, Ptr);
395 bool WritingOffTheEnd = isUserWritingOffTheEnd(ASTCtx, OP);
396
397 // Either the size of the full variable (Kind = 0 or 2) or the size of the
398 // closest surrounding variable (Kind = 1 or 3).
399 std::optional<unsigned> FullSize =
400 computeOpaqueSize(ASTCtx, Ptr, UseClosestSurroundingVariable,
401 WritingOffTheEnd, DetermineForCompleteObject);
402
403 if (!FullSize)
404 return std::nullopt;
405
406 // Similar to the FullSize above, the offset is relative either to the full
407 // variable or to the closest surrounding variable.
408 bool OffsetIsNegative = false;
409 std::optional<uint64_t> Offset = computeOpaquePtrOffset(
410 ASTCtx, Ptr, UseClosestSurroundingVariable, OffsetIsNegative);
411
412 if (!Offset)
413 return std::nullopt;
414
415 if (OffsetIsNegative)
416 return 0u;
417
418 // For __builtin_dynamic_object_size on a counted_by-annotated flexible
419 // array member, defer to IR generation (emitCountedBySize in CGBuiltin):
420 // its runtime computation uses the live 'count' field and is more accurate
421 // than the layout/initializer-derived size we'd produce here. Use the same
422 // findStructFieldAccess form-recognition CGBuiltin does, so we refuse to
423 // fold on exactly the shapes that path handles (and, importantly, *not*
424 // on '&af.fam' which designates the array-as-a-whole and stays on the
425 // layout-derived path to match GCC).
426 if (IsDynamic) {
427 const auto *ME =
428 dyn_cast_if_present<MemberExpr>(findStructFieldAccess(E));
429 const auto *FD = ME ? dyn_cast<FieldDecl>(ME->getMemberDecl()) : nullptr;
430 if (FD && FD->getType()->isCountAttributedType())
431 return std::nullopt;
432 }
433
434 if (!UseClosestSurroundingVariable || DetermineForCompleteObject) {
435 // Kind=3 wants a lower bound, so we can't fall back to this.
436 if (Kind == 3 && !DetermineForCompleteObject)
437 return std::nullopt;
438
439 if (InvalidBase)
440 return std::nullopt;
441
442 QualType ObjectTy = OP.getObjectType();
443 if (ObjectTy->isIncompleteType() || isa<VariableArrayType>(ObjectTy) ||
444 ObjectTy->isFunctionType())
445 return std::nullopt;
446 }
447
448 *Offset += Ptr.getByteOffset();
449
450 if (*Offset > *FullSize)
451 return 0u;
452
453 if (Kind == 1 && InvalidBase && WritingOffTheEnd)
454 return std::nullopt;
455
456 assert(*Offset <= *FullSize);
457 return static_cast<unsigned>(*FullSize - *Offset);
458 }
459
460 // ----------------------------------------------------------------------------------------------------
461
462 if (Ptr.isDummy() && Ptr.getType()->isPointerType())
463 return std::nullopt;
464
465 if (!Ptr.isBlockPointer())
466 return std::nullopt;
467
468 if (Ptr.isDummy()) {
469 if (const VarDecl *VD = Ptr.getRootVarDecl();
470 VD && VD->getType()->isPointerType())
471 InvalidBase = true;
472 }
473
474 bool UseFieldDesc = (Kind & 1u);
475 bool ReportMinimum = (Kind & 2u);
476
477 // According to the GCC documentation, we want the size of the subobject
478 // denoted by the pointer. But that's not quite right -- what we actually
479 // want is the size of the immediately-enclosing array, if there is one.
480 if (Ptr.isArrayElement())
481 Ptr = Ptr.expand();
482
483 bool DetermineForCompleteObject = Ptr.getFieldDesc() == Ptr.getDeclDesc();
484 const Descriptor *DeclDesc = Ptr.getDeclDesc();
485 assert(DeclDesc);
486
487 if (!UseFieldDesc || DetermineForCompleteObject) {
488 // Can't read beyond the pointer decl desc.
489 if (!ReportMinimum && DeclDesc->getDataType(ASTCtx)->isPointerType())
490 return std::nullopt;
491
492 if (InvalidBase)
493 return std::nullopt;
494 } else {
495 if (isUserWritingOffTheEnd(ASTCtx, Ptr, InvalidBase)) {
496 // If we cannot determine the size of the initial allocation, then we
497 // can't given an accurate upper-bound. However, we are still able to give
498 // conservative lower-bounds for Type=3.
499 if (Kind == 1)
500 return std::nullopt;
501 }
502 }
503
504 // The "closest surrounding subobject" is NOT a base class,
505 // so strip the base class casts.
506 if (UseFieldDesc && Ptr.isBaseClass())
507 Ptr = Ptr.stripBaseCasts();
508
509 const Descriptor *Desc = UseFieldDesc ? Ptr.getFieldDesc() : DeclDesc;
510 assert(Desc);
511
512 std::optional<unsigned> FullSize = computeFullDescSize(ASTCtx, Desc);
513 if (!FullSize)
514 return std::nullopt;
515
516 unsigned ByteOffset;
517 if (UseFieldDesc) {
518 if (Ptr.isBaseClass()) {
519 assert(computePointerOffset(ASTCtx, Ptr.getBase()) <=
520 computePointerOffset(ASTCtx, Ptr));
521 ByteOffset = computePointerOffset(ASTCtx, Ptr.getBase()) -
522 computePointerOffset(ASTCtx, Ptr);
523 } else {
524 if (Ptr.inArray())
525 ByteOffset =
526 computePointerOffset(ASTCtx, Ptr) -
527 computePointerOffset(ASTCtx, Ptr.expand().atIndex(0).narrow());
528 else
529 ByteOffset = 0;
530 }
531 } else
532 ByteOffset = computePointerOffset(ASTCtx, Ptr);
533
534 assert(ByteOffset <= *FullSize);
535 return *FullSize - ByteOffset;
536}
537} // namespace interp
538} // namespace clang
static bool pointsToCompleteObject(const ASTContext &ASTCtx, const Pointer &Ptr)
Check if the given pointer points to the complete object, i.e.
static bool pointsToLastObject(const Pointer &Ptr)
Does Ptr point to the last subobject?
static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const Pointer &Ptr, bool InvalidBase)
Does Ptr point to the last object AND to a flexible array member?
static std::optional< unsigned > computeOpaqueSize(const ASTContext &ASTCtx, const Pointer &Ptr, bool UseClosestSurroundingVariable, bool WritingOffTheEnd, bool DetermineForCompleteObject)
static QualType computeFieldType(const ASTContext &ASTCtx, const OpaquePointer &OP, unsigned TypeModifier=0)
static std::optional< uint64_t > computeOpaquePtrOffset(const ASTContext &ASTCtx, const Pointer &Ptr, bool UseClosestSurroundingVariable, bool &OffsetIsNegative)
Determine the offset of the given pointer.
static unsigned computePointerOffset(const ASTContext &ASTCtx, const Pointer &Ptr)
Compute the byte offset of Ptr in the full declaration.
static std::optional< unsigned > computeFullDescSize(const ASTContext &ASTCtx, const Descriptor *Desc)
static bool hasLayout(const RecordDecl *D)
Whether layout (offset and size) information can be queried for D.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
const LangOptions & getLangOpts() const
Definition ASTContext.h:985
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
CanQualType getCanonicalTagType(const TagDecl *TD) const
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3836
QualType getElementType() const
Definition TypeBase.h:3848
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
This represents one expression.
Definition Expr.h:113
Represents a member of a struct/union/class.
Definition Decl.h:3295
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3380
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3531
A (possibly-)qualified type.
Definition TypeBase.h:938
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition TypeBase.h:8687
Represents a struct/union/class.
Definition Decl.h:4460
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
Definition Decl.h:4676
bool isUnion() const
Definition Decl.h:4063
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isArrayType() const
Definition TypeBase.h:8838
bool isPointerType() const
Definition TypeBase.h:8739
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9391
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
Definition Type.cpp:2559
bool isFunctionType() const
Definition TypeBase.h:8735
QualType getType() const
Definition Decl.h:724
Represents a variable declaration or definition.
Definition Decl.h:933
A pointer to a memory block, live or dead.
Definition Pointer.h:531
Pointer getArray() const
Returns the parent array.
Definition Pointer.h:711
bool isArrayElement() const
Checks if the pointer points to an array.
Definition Pointer.h:808
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition Pointer.h:709
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:815
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:873
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition Pointer.h:649
bool isBaseClass() const
Checks if a structure is a base class.
Definition Pointer.h:938
const Record * getRecord() const
Returns the record descriptor of a class.
Definition Pointer.h:865
Structure/Class descriptor.
Definition Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition Record.h:65
unsigned getNumFields() const
Definition Record.h:94
UnsignedOrNone evaluateBuiltinObjectSize(const ASTContext &ASTCtx, unsigned Kind, Pointer &Ptr, const Expr *E, bool IsDynamic)
Evaluate __builtin_object_size or __builtin_dynamic_object_size for the given pointer and Kind.
bool Add(InterpState &S, CodePtr OpPC)
Definition Interp.h:418
static bool validType(QualType T)
Definition Interp.cpp:3285
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
const Expr * findStructFieldAccess(const Expr *E, const Expr **OutArrayIndex=nullptr, QualType *OutArrayElementTy=nullptr)
Walk E through parens, implicit casts, unary &/*, array subscripts and comma operators to find the he...
Definition Expr.cpp:5794
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 uint8_t
Describes a memory block created by an allocation site.
Definition Descriptor.h:122
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:260
QualType getType() const
QualType getDataType(const ASTContext &Ctx) const
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:265
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:146
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:263
const ValueDecl * Base
Definition Pointer.h:433
QualType getObjectType() const
Definition Pointer.h:469
QualType getSurroundingArray() const
If this is pointing to an array element, return the array.
Definition Pointer.cpp:1341
const PointerPathEntry * Path
Definition Pointer.h:436
ArrayRef< PointerPathEntry > path() const
Definition Pointer.h:439
bool isArrayElement() const
Definition Pointer.h:482
enum clang::interp::PointerPathEntry::@133156275124227243235357227301330162015140142322 Kind