clang 23.0.0git
InterpBuiltinBitCast.cpp
Go to the documentation of this file.
1//===-------------------- InterpBuiltinBitCast.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//===----------------------------------------------------------------------===//
9#include "BitcastBuffer.h"
10#include "Boolean.h"
11#include "Char.h"
12#include "Context.h"
13#include "Floating.h"
14#include "Integral.h"
15#include "InterpState.h"
16#include "MemberPointer.h"
17#include "Pointer.h"
18#include "Record.h"
22
23#include <variant>
24
25using namespace clang;
26using namespace clang::interp;
27
28/// Implement __builtin_bit_cast and related operations.
29/// Since our internal representation for data is more complex than
30/// something we can simply memcpy or memcmp, we first bitcast all the data
31/// into a buffer, which we then later use to copy the data into the target.
32
33// TODO:
34// - Try to minimize heap allocations.
35// - Optimize the common case of only pushing and pulling full
36// bytes to/from the buffer.
37
38enum class Result { Success, Skip, Failure };
39
40/// Used to iterate over pointer fields.
41using DataFunc =
42 llvm::function_ref<Result(PtrView P, PrimType Ty, Bits BitOffset,
43 Bits FullBitWidth, bool PackedBools)>;
44
45#define BITCAST_TYPE_SWITCH(Expr, B) \
46 do { \
47 switch (Expr) { \
48 TYPE_SWITCH_CASE(PT_Sint8, B) \
49 TYPE_SWITCH_CASE(PT_Uint8, B) \
50 TYPE_SWITCH_CASE(PT_Sint16, B) \
51 TYPE_SWITCH_CASE(PT_Uint16, B) \
52 TYPE_SWITCH_CASE(PT_Sint32, B) \
53 TYPE_SWITCH_CASE(PT_Uint32, B) \
54 TYPE_SWITCH_CASE(PT_Sint64, B) \
55 TYPE_SWITCH_CASE(PT_Uint64, B) \
56 TYPE_SWITCH_CASE(PT_IntAP, B) \
57 TYPE_SWITCH_CASE(PT_IntAPS, B) \
58 TYPE_SWITCH_CASE(PT_Bool, B) \
59 default: \
60 llvm_unreachable("Unhandled bitcast type"); \
61 } \
62 } while (0)
63
64#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \
65 do { \
66 switch (Expr) { \
67 TYPE_SWITCH_CASE(PT_Sint8, B) \
68 TYPE_SWITCH_CASE(PT_Uint8, B) \
69 TYPE_SWITCH_CASE(PT_Sint16, B) \
70 TYPE_SWITCH_CASE(PT_Uint16, B) \
71 TYPE_SWITCH_CASE(PT_Sint32, B) \
72 TYPE_SWITCH_CASE(PT_Uint32, B) \
73 TYPE_SWITCH_CASE(PT_Sint64, B) \
74 TYPE_SWITCH_CASE(PT_Uint64, B) \
75 TYPE_SWITCH_CASE(PT_Bool, B) \
76 default: \
77 llvm_unreachable("Unhandled bitcast type"); \
78 } \
79 } while (0)
80
81/// We use this to recursively iterate over all fields and elements of a pointer
82/// and extract relevant data for a bitcast.
83static Result enumerateData(PtrView P, const Context &Ctx, Bits Offset,
84 Bits BitsToRead, DataFunc F, bool Initialize) {
85 const Descriptor *FieldDesc = P.getFieldDesc();
86 assert(FieldDesc);
87
88 // Primitives.
89 if (FieldDesc->isPrimitive()) {
90 Bits FullBitWidth =
91 Bits(Ctx.getASTContext().getTypeSize(FieldDesc->getType()));
92 return F(P, FieldDesc->getPrimType(), Offset, FullBitWidth,
93 /*PackedBools=*/false);
94 }
95
96 // Primitive arrays.
97 if (FieldDesc->isPrimitiveArray()) {
98 QualType ElemType = FieldDesc->getElemQualType();
99 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
100 PrimType ElemT = *Ctx.classify(ElemType);
101 // Special case, since the bools here are packed.
102 bool PackedBools =
103 FieldDesc->getType()->isPackedVectorBoolType(Ctx.getASTContext());
104 unsigned NumElems = FieldDesc->getNumElems();
105 bool Ok = true;
106 for (unsigned I = P.getIndex(); I != NumElems; ++I) {
107 Result Res = F(P.atIndex(I), ElemT, Offset, ElemSize, PackedBools);
108
109 Ok = Ok && (Res == Result::Success);
110 Offset += PackedBools ? Bits(1) : ElemSize;
111 if (Offset >= BitsToRead)
112 break;
113 }
115 }
116
117 // Composite arrays.
118 if (FieldDesc->isCompositeArray()) {
119 QualType ElemType = FieldDesc->getElemQualType();
120 Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
121 for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) {
122 enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F,
123 Initialize);
124 Offset += ElemSize;
125 if (Offset >= BitsToRead)
126 break;
127 }
128 return Result::Success;
129 }
130
131 // Records.
132 if (FieldDesc->isRecord()) {
133 const Record *R = FieldDesc->ElemRecord;
134 if (R->getDecl()->isInvalidDecl())
135 return Result::Failure;
136 const ASTRecordLayout &Layout =
137 Ctx.getASTContext().getASTRecordLayout(R->getDecl());
138 bool Ok = true;
139
140 for (const Record::Field &Fi : R->fields()) {
141 if (Fi.isUnnamedBitField())
142 continue;
143
144 PtrView Elem = P.atField(Fi.Offset);
145 Bits BitOffset =
146 Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
147 Result Res =
148 enumerateData(Elem, Ctx, BitOffset, BitsToRead, F, Initialize);
149 if (Initialize) {
150 if (Res == Result::Success)
151 Elem.initialize();
152 else if (Res == Result::Skip)
153 Elem.startLifetime();
154 }
155 Ok = Ok && Res != Result::Failure;
156 }
157 for (const Record::Base &B : R->bases()) {
158 PtrView Elem = P.atField(B.Offset);
159 if (!Initialize && !Elem.isInitialized())
160 return Result::Failure;
161
162 CharUnits ByteOffset =
164 Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
165 Result Res =
166 enumerateData(Elem, Ctx, BitOffset, BitsToRead, F, Initialize);
167 if (Initialize) {
168 if (Res == Result::Success)
169 Elem.initialize();
170 else if (Res == Result::Skip)
171 Elem.startLifetime();
172 }
173 Ok = Ok && Res != Result::Failure;
174 }
176 }
177
178 llvm_unreachable("Unhandled data type");
179}
180
181static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
182 Bits BitsToRead, DataFunc F,
183 bool Initialize) {
184
185 return enumerateData(P.view(), Ctx, Bits::zero(), BitsToRead, F,
186 Initialize) != Result::Failure;
187}
188
189// This function is constexpr if and only if To, From, and the types of
190// all subobjects of To and From are types T such that...
191// (3.1) - is_union_v<T> is false;
192// (3.2) - is_pointer_v<T> is false;
193// (3.3) - is_member_pointer_v<T> is false;
194// (3.4) - is_volatile_v<T> is false; and
195// (3.5) - T has no non-static data members of reference type
196//
197// NOTE: This is a version of checkBitCastConstexprEligibilityType() in
198// ExprConstant.cpp.
200 bool IsToType) {
201 enum {
202 E_Union = 0,
203 E_Pointer,
204 E_MemberPointer,
205 E_Volatile,
206 E_Reference,
207 };
208 enum { C_Member, C_Base };
209
210 auto diag = [&](int Reason) -> bool {
211 const Expr *E = S.Current->getExpr(OpPC);
212 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type)
213 << static_cast<int>(IsToType) << (Reason == E_Reference) << Reason
214 << E->getSourceRange();
215 return false;
216 };
217 auto note = [&](int Construct, QualType NoteType,
218 SourceRange NoteRange) -> bool {
219 S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)
220 << NoteType << Construct << T.getUnqualifiedType() << NoteRange;
221 return false;
222 };
223 auto unsupported = [&](QualType T) -> bool {
224 S.FFDiag(S.Current->getSource(OpPC),
225 diag::note_constexpr_bit_cast_unsupported_type)
226 << T;
227 return false;
228 };
229
230 T = T.getCanonicalType();
231
232 if (T->isUnionType())
233 return diag(E_Union);
234 if (T->isPointerType())
235 return diag(E_Pointer);
236 if (T->isMemberPointerType())
237 return diag(E_MemberPointer);
238 if (T.isVolatileQualified())
239 return diag(E_Volatile);
240
241 if (const RecordDecl *RD = T->getAsRecordDecl()) {
242 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
243 for (const CXXBaseSpecifier &BS : CXXRD->bases()) {
244 if (!CheckBitcastType(S, OpPC, BS.getType(), IsToType))
245 return note(C_Base, BS.getType(), BS.getBeginLoc());
246 }
247 }
248 for (const FieldDecl *FD : RD->fields()) {
249 if (FD->getType()->isReferenceType())
250 return diag(E_Reference);
251 if (!CheckBitcastType(S, OpPC, FD->getType(), IsToType))
252 return note(C_Member, FD->getType(), FD->getSourceRange());
253 }
254 }
255
256 if (T->isArrayType() &&
258 IsToType))
259 return false;
260
261 if (const auto *VT = T->getAs<VectorType>()) {
262 const ASTContext &ASTCtx = S.getASTContext();
263 QualType EltTy = VT->getElementType();
264 unsigned NElts = VT->getNumElements();
265 unsigned EltSize =
266 VT->isPackedVectorBoolType(ASTCtx) ? 1 : ASTCtx.getTypeSize(EltTy);
267
268 if ((NElts * EltSize) % ASTCtx.getCharWidth() != 0) {
269 // The vector's size in bits is not a multiple of the target's byte size,
270 // so its layout is unspecified. For now, we'll simply treat these cases
271 // as unsupported (this should only be possible with OpenCL bool vectors
272 // whose element count isn't a multiple of the byte size).
273 const Expr *E = S.Current->getExpr(OpPC);
274 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_vector)
275 << QualType(VT, 0) << EltSize << NElts << ASTCtx.getCharWidth();
276 return false;
277 }
278
279 if (EltTy->isRealFloatingType() &&
280 &ASTCtx.getFloatTypeSemantics(EltTy) == &APFloat::x87DoubleExtended()) {
281 // The layout for x86_fp80 vectors seems to be handled very inconsistently
282 // by both clang and LLVM, so for now we won't allow bit_casts involving
283 // it in a constexpr context.
284 return unsupported(EltTy);
285 }
286 }
287
288 if (T->isBlockPointerType())
289 return unsupported(T);
290
291 return true;
292}
293
295 const Pointer &FromPtr,
296 BitcastBuffer &Buffer,
297 bool ReturnOnUninit) {
298 const ASTContext &ASTCtx = Ctx.getASTContext();
299 Endian TargetEndianness =
301
303 FromPtr, Ctx, Buffer.size(),
304 [&](PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
305 bool PackedBools) -> Result {
306 Bits BitWidth = FullBitWidth;
307
308 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
309 BitWidth = Bits(std::min(FD->getBitWidthValue(),
310 (unsigned)FullBitWidth.getQuantity()));
311 else if (T == PT_Bool && PackedBools)
312 BitWidth = Bits(1);
313
314 if (BitWidth.isZero())
315 return Result::Skip;
316
317 // Bits will be left uninitialized and diagnosed when reading.
318 if (!P.isInitialized())
319 return Result::Skip;
320
321 if (T == PT_Ptr) {
322 assert(P.getType()->isNullPtrType());
323 // Clang treats nullptr_t has having NO bits in its value
324 // representation. So, we accept it here and leave its bits
325 // uninitialized.
326 return Result::Skip;
327 }
328
329 assert(P.isInitialized());
330 auto Buff = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes());
331 // Work around floating point types that contain unused padding bytes.
332 // This is really just `long double` on x86, which is the only
333 // fundamental type with padding bytes.
334 if (T == PT_Float) {
335 const Floating &F = P.deref<Floating>();
336 Bits NumBits = Bits(
337 llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics()));
338 assert(NumBits.isFullByte());
339 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
340 F.bitcastToMemory(Buff.get());
341 // Now, only (maybe) swap the actual size of the float, excluding
342 // the padding bits.
343 if (llvm::sys::IsBigEndianHost)
344 swapBytes(Buff.get(), NumBits.roundToBytes());
345
346 Buffer.markInitialized(BitOffset, NumBits);
347 } else {
349 auto Val = P.deref<T>();
350 if (!Val.isNumber())
351 return Result::Failure;
352 Val.bitcastToMemory(Buff.get());
353 });
354
355 if (llvm::sys::IsBigEndianHost)
356 swapBytes(Buff.get(), FullBitWidth.roundToBytes());
357 Buffer.markInitialized(BitOffset, BitWidth);
358 }
359
360 Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
361 return Result::Success;
362 },
363 false);
364}
365
367 std::byte *Buff, Bits BitWidth, Bits FullBitWidth,
368 bool &HasIndeterminateBits) {
369 assert(Ptr.isLive());
370 assert(Ptr.isBlockPointer());
371 assert(Buff);
372 assert(BitWidth <= FullBitWidth);
373 assert(FullBitWidth.isFullByte());
374 assert(BitWidth.isFullByte());
375
376 BitcastBuffer Buffer(FullBitWidth);
377 size_t BuffSize = FullBitWidth.roundToBytes();
378 QualType DataType = Ptr.getFieldDesc()->getDataType(S.getASTContext());
379 if (!CheckBitcastType(S, OpPC, DataType, /*IsToType=*/false))
380 return false;
381
382 bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer,
383 /*ReturnOnUninit=*/false);
384 HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth);
385
386 const ASTContext &ASTCtx = S.getASTContext();
387 Endian TargetEndianness =
389 auto B =
390 Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness);
391
392 std::memcpy(Buff, B.get(), BuffSize);
393
394 if (llvm::sys::IsBigEndianHost)
395 swapBytes(Buff, BitWidth.roundToBytes());
396
397 return Success;
398}
400 const Pointer &FromPtr, Pointer &ToPtr) {
401 const ASTContext &ASTCtx = S.getASTContext();
402 CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(ToPtr.getType());
403
404 return DoBitCastPtr(S, OpPC, FromPtr, ToPtr, ObjectReprChars.getQuantity());
405}
406
408 const Pointer &FromPtr, Pointer &ToPtr,
409 size_t Size) {
410 assert(FromPtr.isLive());
411 assert(FromPtr.isBlockPointer());
412 assert(ToPtr.isBlockPointer());
413
414 QualType FromType = FromPtr.getFieldDesc()->getDataType(S.getASTContext());
415 QualType ToType = ToPtr.getFieldDesc()->getDataType(S.getASTContext());
416
417 if (!CheckBitcastType(S, OpPC, ToType, /*IsToType=*/true))
418 return false;
419 if (!CheckBitcastType(S, OpPC, FromType, /*IsToType=*/false))
420 return false;
421
422 const ASTContext &ASTCtx = S.getASTContext();
423 BitcastBuffer Buffer(Bytes(Size).toBits());
424 readPointerToBuffer(S.getContext(), FromPtr, Buffer,
425 /*ReturnOnUninit=*/false);
426
427 // Now read the values out of the buffer again and into ToPtr.
428 Endian TargetEndianness =
431 ToPtr, S.getContext(), Buffer.size(),
432 [&](PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
433 bool PackedBools) -> Result {
434 QualType PtrType = P.getType();
435 if (T == PT_Float) {
436 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType);
437 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics));
438 assert(NumBits.isFullByte());
439 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
440 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth,
441 TargetEndianness);
442
443 if (llvm::sys::IsBigEndianHost)
444 swapBytes(M.get(), NumBits.roundToBytes());
445
446 Floating R = S.allocFloat(Semantics);
447 Floating::bitcastFromMemory(M.get(), Semantics, &R);
448 P.deref<Floating>() = R;
449 P.initialize();
450 return Result::Success;
451 }
452
453 Bits BitWidth;
454 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
455 BitWidth = Bits(std::min(FD->getBitWidthValue(),
456 (unsigned)FullBitWidth.getQuantity()));
457 else if (T == PT_Bool && PackedBools)
458 BitWidth = Bits(1);
459 else
460 BitWidth = FullBitWidth;
461
462 // If any of the bits are uninitialized, we need to abort unless the
463 // target type is std::byte or unsigned char.
464 bool Initialized = Buffer.rangeInitialized(BitOffset, BitWidth);
465 if (!Initialized) {
466 if (!PtrType->isStdByteType() &&
467 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) &&
468 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) {
469 const Expr *E = S.Current->getExpr(OpPC);
470 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
471 << PtrType << S.getLangOpts().CharIsSigned
472 << E->getSourceRange();
473
474 return Result::Failure;
475 }
476 return Result::Skip;
477 }
478
479 auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth,
480 TargetEndianness);
481 if (llvm::sys::IsBigEndianHost)
482 swapBytes(Memory.get(), FullBitWidth.roundToBytes());
483
484 if (T == PT_IntAPS) {
486 S.allocAP<IntegralAP<true>>(FullBitWidth.getQuantity());
488 FullBitWidth.getQuantity(),
489 &P.deref<IntegralAP<true>>());
490 } else if (T == PT_IntAP) {
492 S.allocAP<IntegralAP<false>>(FullBitWidth.getQuantity());
494 FullBitWidth.getQuantity(),
496 } else {
498 if (BitWidth.nonZero())
499 P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth())
500 .truncate(BitWidth.getQuantity());
501 else
502 P.deref<T>() = T::zero();
503 });
504 }
505 P.initialize();
506 return Result::Success;
507 },
508 true);
509
510 return Success;
511}
512
519
520// NB: This implementation isn't exactly ideal, but:
521// 1) We can't just do a bitcast here since we need to be able to
522// copy pointers.
523// 2) This also needs to handle overlapping regions.
524// 3) We currently have no way of iterating over the fields of a pointer
525// backwards.
527 const Pointer &SrcPtr, const Pointer &DestPtr,
528 Bits Size) {
529 assert(SrcPtr.isBlockPointer());
530 assert(DestPtr.isBlockPointer());
531
534 SrcPtr, S.getContext(), Size,
535 [&](const PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
536 bool PackedBools) -> Result {
537 TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); });
538 return Result::Success;
539 },
540 false);
541
542 unsigned ValueIndex = 0;
544 DestPtr, S.getContext(), Size,
545 [&](const PtrView P, PrimType T, Bits BitOffset, Bits FullBitWidth,
546 bool PackedBools) -> Result {
547 TYPE_SWITCH(T, {
548 P.deref<T>() = std::get<T>(Values[ValueIndex]);
549 P.initialize();
550 });
551
552 ++ValueIndex;
553 return Result::Success;
554 },
555 true);
556
557 // We should've read all the values into DestPtr.
558 assert(ValueIndex == Values.size());
559
560 return true;
561}
Defines the clang::ASTContext interface.
std::variant< Pointer, FunctionPointer, MemberPointer, FixedPoint, Char< false >, Char< true >, Integral< 16, false >, Integral< 16, true >, Integral< 32, false >, Integral< 32, true >, Integral< 64, false >, Integral< 64, true >, IntegralAP< true >, IntegralAP< false >, Boolean, Floating > PrimTypeVariant
static Result enumerateData(PtrView P, const Context &Ctx, Bits Offset, Bits BitsToRead, DataFunc F, bool Initialize)
We use this to recursively iterate over all fields and elements of a pointer and extract relevant dat...
#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B)
Result
Implement __builtin_bit_cast and related operations.
static bool enumeratePointerFields(const Pointer &P, const Context &Ctx, Bits BitsToRead, DataFunc F, bool Initialize)
llvm::function_ref< Result(PtrView P, PrimType Ty, Bits BitOffset, Bits FullBitWidth, bool PackedBools)> DataFunc
Used to iterate over pointer fields.
#define BITCAST_TYPE_SWITCH(Expr, B)
static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, bool IsToType)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
const llvm::fltSemantics & getFloatTypeSemantics(QualType T) const
Return the APFloat 'semantics' for the specified scalar floating point type.
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
int64_t toBits(CharUnits CharSize) const
Convert a size in characters to a size in bits.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:921
uint64_t getCharWidth() const
Return the size of the character type, in bits.
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 a base class of a C++ class.
Definition DeclCXX.h:146
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:112
Represents a member of a struct/union/class.
Definition Decl.h:3182
bool isBitField() const
Determines whether this field is a bitfield.
Definition Decl.h:3285
A (possibly-)qualified type.
Definition TypeBase.h:937
Represents a struct/union/class.
Definition Decl.h:4347
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
bool isLittleEndian() const
bool isPackedVectorBoolType(const ASTContext &ctx) const
Definition Type.cpp:455
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2405
Represents a GCC generic vector type.
Definition TypeBase.h:4239
Wrapper around boolean types.
Definition Boolean.h:25
Pointer into the code segment.
Definition Source.h:30
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:47
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:101
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:424
Wrapper around fixed point types.
Definition FixedPoint.h:23
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition Floating.h:35
void bitcastToMemory(std::byte *Buff) const
Definition Floating.h:191
APFloat getAPFloat() const
Definition Floating.h:64
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition IntegralAP.h:36
static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth, IntegralAP *Result)
Definition IntegralAP.h:207
Wrapper around numeric types.
Definition Integral.h:69
const Expr * getExpr(CodePtr PC) const
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
Interpreter context.
Definition InterpState.h:36
Context & getContext() const
Definition InterpState.h:72
InterpFrame * Current
The current frame.
T allocAP(unsigned BitWidth)
A pointer to a memory block, live or dead.
Definition Pointer.h:394
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:563
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:511
bool isBlockPointer() const
Definition Pointer.h:668
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:553
PtrView view() const
Definition Pointer.h:450
Structure/Class descriptor.
Definition Record.h:25
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition State.cpp:66
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation could not be folded (FF => FoldFailure)
Definition State.cpp:21
ASTContext & getASTContext() const
Definition State.h:92
const LangOptions & getLangOpts() const
Definition State.h:93
Defines the clang::TargetInfo interface.
bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, BitcastBuffer &Buffer, bool ReturnOnUninit)
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr)
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)
Copy the contents of Src into Dest.
bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, bool &HasIndeterminateBits)
static void swapBytes(std::byte *M, size_t N)
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
@ Success
Annotation was successful.
Definition Parser.h:65
@ Result
The result type of a method or function.
Definition TypeBase.h:905
U cast(CodeGen::Address addr)
Definition Address.h:327
Track what bits have been initialized to known values and which ones have indeterminate value.
std::unique_ptr< std::byte[]> copyBits(Bits BitOffset, Bits BitWidth, Bits FullBitWidth, Endian TargetEndianness) const
Copy BitWidth bits at offset BitOffset from the buffer.
void markInitialized(Bits Start, Bits Length)
Marks the bits in the given range as initialized.
bool rangeInitialized(Bits Offset, Bits Length) const
Bits size() const
Returns the buffer size in bits.
void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth, Endian TargetEndianness)
Push BitWidth bits at BitOffset from In into the buffer.
A quantity in bits.
size_t roundToBytes() const
bool isFullByte() const
static Bits zero()
size_t getQuantity() const
A quantity in bytes.
Describes a memory block created by an allocation site.
Definition Descriptor.h:123
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:260
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:274
QualType getElemQualType() const
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition Descriptor.h:267
QualType getType() const
QualType getDataType(const ASTContext &Ctx) const
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:265
PrimType getPrimType() const
Definition Descriptor.h:242
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:279
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:154
PtrView atField(unsigned Offset) const
Definition Pointer.h:253
const Descriptor * getFieldDesc() const
Definition Pointer.h:77
const FieldDecl * getField() const
Definition Pointer.h:150
PtrView atIndex(unsigned Idx) const
Definition Pointer.h:189
void startLifetime() const
Definition Pointer.h:310
PtrView narrow() const
Definition Pointer.h:87
bool isInitialized() const
Definition Pointer.h:281
void initialize() const
Definition Pointer.cpp:554
T & deref() const
Definition Pointer.h:224
int64_t getIndex() const
Definition Pointer.h:198