clang: lib/AST/ByteCode/Context.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
24
25using namespace clang;
27
29 this->ShortWidth = Ctx.getTargetInfo().getShortWidth();
30 this->IntWidth = Ctx.getTargetInfo().getIntWidth();
31 this->LongWidth = Ctx.getTargetInfo().getLongWidth();
32 this->LongLongWidth = Ctx.getTargetInfo().getLongLongWidth();
33 assert(Ctx.getTargetInfo().getCharWidth() == 8 &&
34 "We're assuming 8 bit chars");
35}
36
38
40 assert(Stk.empty());
41
42
45 return false;
46
47
50
51 if (->isValid())
52 return false;
53
54 ++EvalID;
55
56 return Run(Parent, Func);
57}
58
61 assert(Stk.empty());
62 ++EvalID;
63 size_t StackSizeBefore = Stk.size();
65
66 if (.interpretCall(FD, E)) {
67 C.cleanup();
68 Stk.clearTo(StackSizeBefore);
69 }
70}
71
73 ++EvalID;
74 bool Recursing = !Stk.empty();
75 size_t StackSizeBefore = Stk.size();
77
78 auto Res = C.interpretExpr(E, E->isGLValue());
79
80 if (Res.isInvalid()) {
81 C.cleanup();
82 Stk.clearTo(StackSizeBefore);
83 return false;
84 }
85
86 if (!Recursing) {
87
88
89 C.cleanup();
90#ifndef NDEBUG
91
92
93 Stk.clearTo(StackSizeBefore);
94#endif
95 }
96
97 Result = Res.stealAPValue();
98
99 return true;
100}
101
104 ++EvalID;
105 bool Recursing = !Stk.empty();
106 size_t StackSizeBefore = Stk.size();
108
109 auto Res = C.interpretExpr(E, false,
110 true);
111 if (Res.isInvalid()) {
112 C.cleanup();
113 Stk.clearTo(StackSizeBefore);
114 return false;
115 }
116
117 if (!Recursing) {
118 assert(Stk.empty());
119 C.cleanup();
120#ifndef NDEBUG
121
122
123 Stk.clearTo(StackSizeBefore);
124#endif
125 }
126
127 Result = Res.stealAPValue();
128 return true;
129}
130
133 ++EvalID;
134 bool Recursing = !Stk.empty();
135 size_t StackSizeBefore = Stk.size();
137
138 bool CheckGlobalInitialized =
141 auto Res = C.interpretDecl(VD, Init, CheckGlobalInitialized);
142 if (Res.isInvalid()) {
143 C.cleanup();
144 Stk.clearTo(StackSizeBefore);
145
146 return false;
147 }
148
149 if (!Recursing) {
150 assert(Stk.empty());
151 C.cleanup();
152#ifndef NDEBUG
153
154
155 Stk.clearTo(StackSizeBefore);
156#endif
157 }
158
159 Result = Res.stealAPValue();
160 return true;
161}
162
163template
164bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,
165 const Expr *PtrExpr, ResultT &Result) {
166 assert(Stk.empty());
168
169
172 return false;
173
174 if (!SizeValue.isInt())
175 return false;
176 uint64_t Size = SizeValue.getInt().getZExtValue();
177
178 auto PtrRes = C.interpretAsPointer(PtrExpr, [&](const Pointer &Ptr) {
179 if (Size == 0) {
180 if constexpr (std::is_same_v<ResultT, APValue>)
182 return true;
183 }
184
186 return false;
187
188
190 return false;
191
193 Parent.FFDiag(SizeExpr, diag::note_constexpr_access_past_end) << AK_Read;
195 }
196
197 if constexpr (std::is_same_v<ResultT, APValue>) {
200 for (uint64_t I = 0; I != Size; ++I) {
201 if (std::optional ElemVal =
203 Result.getArrayInitializedElt(I) = *ElemVal;
204 else
205 return false;
206 }
207 } else {
208 assert((std::is_same_v<ResultT, std::string>));
209 if (Size < Result.max_size())
211 Result.assign(reinterpret_cast<const char *>(Ptr.getRawAddress()), Size);
212 }
213
214 return true;
215 });
216
217 if (PtrRes.isInvalid()) {
218 C.cleanup();
219 Stk.clear();
220 return false;
221 }
222
223 return true;
224}
225
228 assert(SizeExpr);
229 assert(PtrExpr);
230
231 return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);
232}
233
235 const Expr *PtrExpr, std::string &Result) {
236 assert(SizeExpr);
237 assert(PtrExpr);
238
239 return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);
240}
241
243 std::string &Result) {
244 assert(Stk.empty());
246
247 auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {
250 return false;
251
253 return false;
254
256
257 if (Ptr.elemSize() == 1 ) {
258 const char *Chars = reinterpret_cast<const char *>(Ptr.getRawAddress());
259 unsigned Length = strnlen(Chars, N);
260
261 if (N == Length)
262 return false;
263 Result.assign(Chars, Length);
264 return true;
265 }
266
268 for (unsigned I = Ptr.getIndex(); I != N; ++I) {
270 auto Elem = Ptr.elem<T>(I);
271 if (Elem.isZero())
272 return true;
273 Result.push_back(static_cast<char>(Elem));
274 });
275 }
276
277 return false;
278 });
279
280 if (PtrRes.isInvalid()) {
281 C.cleanup();
282 Stk.clear();
283 return false;
284 }
285 return true;
286}
287
289 assert(Stk.empty());
291
292 auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {
295 return false;
296
298 return false;
299
302 Result = strnlen(reinterpret_cast<const char *>(Ptr.getRawAddress()), N);
304 }
305
308 for (unsigned I = Ptr.getIndex(); I != N; ++I) {
310 auto Elem = Ptr.elem<T>(I);
311 if (Elem.isZero())
312 return true;
314 });
315 }
316
317 return false;
318 });
319
320 if (PtrRes.isInvalid()) {
321 C.cleanup();
322 Stk.clear();
323 return false;
324 }
325 return true;
326}
327
329
331 switch (BitWidth) {
332 case 64:
334 case 32:
336 case 16:
338 case 8:
340 default:
342 }
343 llvm_unreachable("Unhandled BitWidth");
344}
345
347 switch (BitWidth) {
348 case 64:
350 case 32:
352 case 16:
354 case 8:
356 default:
358 }
359 llvm_unreachable("Unhandled BitWidth");
360}
361
363
364 if (const auto *BT = dyn_cast(T.getCanonicalType())) {
365 auto Kind = BT->getKind();
366 if (Kind == BuiltinType::Bool)
368 if (Kind == BuiltinType::NullPtr)
370 if (Kind == BuiltinType::BoundMember)
372
373
374 if (Kind == BuiltinType::Short)
376 if (Kind == BuiltinType::UShort)
378
379 if (Kind == BuiltinType::Int)
381 if (Kind == BuiltinType::UInt)
383 if (Kind == BuiltinType::Long)
385 if (Kind == BuiltinType::ULong)
387 if (Kind == BuiltinType::LongLong)
389 if (Kind == BuiltinType::ULongLong)
391
392 if (Kind == BuiltinType::SChar || Kind == BuiltinType::Char_S)
394 if (Kind == BuiltinType::UChar || Kind == BuiltinType::Char_U ||
395 Kind == BuiltinType::Char8)
397
398 if (BT->isSignedInteger())
400 if (BT->isUnsignedInteger())
402
403 if (BT->isFloatingPoint())
405 }
406
407 if (T->isPointerOrReferenceType())
409
410 if (T->isMemberPointerType())
412
413 if (const auto *BT = T->getAs<BitIntType>()) {
414 if (BT->isSigned())
417 }
418
419 if (const auto *D = T->getAsEnumDecl()) {
420 if (!D->isComplete())
421 return std::nullopt;
422 return classify(D->getIntegerType());
423 }
424
425 if (const auto *AT = T->getAs<AtomicType>())
426 return classify(AT->getValueType());
427
428 if (const auto *DT = dyn_cast(T))
429 return classify(DT->getUnderlyingType());
430
431 if (T->isObjCObjectPointerType() || T->isBlockPointerType())
433
434 if (T->isFixedPointType())
436
437
438 return std::nullopt;
439}
440
442 return Ctx.getTargetInfo().getCharWidth();
443}
444
445
446
448 return Ctx.getFloatTypeSemantics(T);
449}
450
454 assert(Stk.empty());
455 return true;
456 }
458 return false;
459}
460
461
466 assert(DynamicDecl);
467 assert(StaticDecl);
468 assert(InitialFunction);
469
471 const CXXMethodDecl *FoundFunction = InitialFunction;
472 for (;;) {
475 if (Overrider)
476 return Overrider;
477
478
481 continue;
482 }
483
484
486 const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();
487 if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {
488 CurRecord = Base;
489 break;
490 }
491 }
492 }
493
494 llvm_unreachable(
495 "Couldn't find an overriding function in the class hierarchy?");
496 return nullptr;
497}
498
500 assert(FuncDecl);
501 if (const Function *Func = P->getFunction(FuncDecl))
503
504
505
507 return nullptr;
508
509 bool IsLambdaStaticInvoker = false;
510 if (const auto *MD = dyn_cast(FuncDecl);
511 MD && MD->isLambdaStaticInvoker()) {
512
513
514
515
516
517 IsLambdaStaticInvoker = true;
518 }
519
523 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
524
525
526
527
529 bool HasRVO = false;
531 HasRVO = true;
532 ParamTypes.push_back(PT_Ptr);
535 }
536
537
538
539
540 bool HasThisPointer = false;
541 if (const auto *MD = dyn_cast(FuncDecl)) {
542 if (!IsLambdaStaticInvoker) {
543 HasThisPointer = MD->isInstance();
544 if (MD->isImplicitObjectMemberFunction()) {
545 ParamTypes.push_back(PT_Ptr);
548 }
549 }
550
552
553
554 if (!MD->getParent()->isCompleteDefinition())
555 return nullptr;
556 llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;
558
559 MD->getParent()->getCaptureFields(LC, LTC);
560
561 if (MD->isStatic() && !LC.empty()) {
562
563
564 return nullptr;
565 }
566 }
567 }
568
569
570
572 for (auto [ParamIndex, PD] : llvm::enumerate(FuncDecl->parameters())) {
573 bool IsConst = PD->getType().isConstQualified();
574 bool IsVolatile = PD->getType().isVolatileQualified();
575
577 FuncProto->getParamType(ParamIndex)))
578 return nullptr;
579
582 Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,
583 IsConst, false,
584 false, IsVolatile);
585
586 ParamDescriptors.insert({ParamOffset, {PT, Desc}});
589 ParamTypes.push_back(PT);
590 }
591
592
593 assert(!P->getFunction(FuncDecl));
595 FuncDecl, ParamOffset, std::move(ParamTypes), std::move(ParamDescriptors),
596 std::move(ParamOffsets), HasThisPointer, HasRVO, IsLambdaStaticInvoker);
598}
599
602
606 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
607
608
609
611 bool IsConst = PD->getType().isConstQualified();
612 bool IsVolatile = PD->getType().isVolatileQualified();
613
616 Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,
617 IsConst, false,
618 false, IsVolatile);
619 ParamDescriptors.insert({ParamOffset, {PT, Desc}});
622 ParamTypes.push_back(PT);
623 }
624
626 return nullptr;
627
628
630 P->createFunction(E, ParamOffset, std::move(ParamTypes),
631 std::move(ParamDescriptors), std::move(ParamOffsets),
632 false, false,
633 false);
634
635 assert(Func);
636 Func->setDefined(true);
637
638 Func->setIsFullyCompiled(true);
640}
641
643 const RecordDecl *DerivedDecl) const {
644 assert(BaseDecl);
645 assert(DerivedDecl);
647 const RecordDecl *CurDecl = DerivedDecl;
648 const Record *CurRecord = P->getOrCreateRecord(CurDecl);
649 assert(CurDecl && FinalDecl);
650
651 unsigned OffsetSum = 0;
652 for (;;) {
654
655 for (const Record::Base &B : CurRecord->bases()) {
657
658 if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {
659 OffsetSum += B.Offset;
660 CurRecord = B.R;
661 CurDecl = BaseDecl;
662 break;
663 }
664 }
665 if (CurDecl == FinalDecl)
666 break;
667 }
668
669 assert(OffsetSum > 0);
670 return OffsetSum;
671}
672
674 return P->getOrCreateRecord(D);
675}
676
678 return ID == Builtin::BI__builtin_classify_type ||
679 ID == Builtin::BI__builtin_os_log_format_buffer_size ||
680 ID == Builtin::BI__builtin_constant_p || ID == Builtin::BI__noop;
681}
This file provides some common utility functions for processing Lambda related AST Constructs.
static PrimType integralTypeToPrimTypeS(unsigned BitWidth)
Definition Context.cpp:330
static PrimType integralTypeToPrimTypeU(unsigned BitWidth)
Definition Context.cpp:346
#define INT_TYPE_SWITCH(Expr, B)
static bool isRecordType(QualType T)
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
A fixed int type of a specified bitwidth.
Represents a block literal declaration, which is like an unnamed FunctionDecl.
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
ArrayRef< ParmVarDecl * > parameters() const
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
Represents a base class of a C++ class.
QualType getType() const
Retrieves the type of the base class.
Represents a static or instance method of a struct/union/class.
CXXMethodDecl * getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD, bool MayBeBase=false)
Find if RD declares a function that overrides this function, and if so, return it.
Represents a C++ struct/union/class.
unsigned getNumBases() const
Retrieves the number of base classes of this class.
base_class_iterator bases_begin()
This represents one expression.
Represents a member of a struct/union/class.
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Represents a function declaration or definition.
QualType getReturnType() const
ArrayRef< ParmVarDecl * > parameters() const
param_iterator param_begin()
Represents a prototype with parameter type info, e.g.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Represents a parameter to a function.
A (possibly-)qualified type.
Represents a struct/union/class.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs'.
Represents a variable declaration or definition.
Compilation context for expressions.
const LangOptions & getLangOpts() const
Returns the language options.
Definition Context.cpp:328
const Function * getOrCreateObjCBlock(const BlockExpr *E)
Definition Context.cpp:600
~Context()
Cleans up the constexpr VM.
Definition Context.cpp:37
Context(ASTContext &Ctx)
Initialises the constexpr VM.
Definition Context.cpp:28
bool evaluateCharRange(State &Parent, const Expr *SizeExpr, const Expr *PtrExpr, APValue &Result)
Definition Context.cpp:226
bool evaluateString(State &Parent, const Expr *E, std::string &Result)
Evaluate.
Definition Context.cpp:242
static bool isUnevaluatedBuiltin(unsigned ID)
Unevaluated builtins don't get their arguments put on the stack automatically.
Definition Context.cpp:677
unsigned getCharBit() const
Returns CHAR_BIT.
Definition Context.cpp:441
bool evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result)
Evalute.
Definition Context.cpp:288
const llvm::fltSemantics & getFloatSemantics(QualType T) const
Return the floating-point semantics for T.
Definition Context.cpp:447
static bool shouldBeGloballyIndexed(const ValueDecl *VD)
Returns whether we should create a global variable for the given ValueDecl.
void isPotentialConstantExprUnevaluated(State &Parent, const Expr *E, const FunctionDecl *FD)
Definition Context.cpp:59
unsigned collectBaseOffset(const RecordDecl *BaseDecl, const RecordDecl *DerivedDecl) const
Definition Context.cpp:642
const Record * getRecord(const RecordDecl *D) const
Definition Context.cpp:673
bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FD)
Checks if a function is a potential constant expression.
Definition Context.cpp:39
const Function * getOrCreateFunction(const FunctionDecl *FuncDecl)
Definition Context.cpp:499
ASTContext & getASTContext() const
Returns the AST context.
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:362
bool canClassify(QualType T) const
bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result)
Evaluates a toplevel expression as an rvalue.
Definition Context.cpp:72
const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, const CXXMethodDecl *InitialFunction) const
Definition Context.cpp:463
bool evaluate(State &Parent, const Expr *E, APValue &Result, ConstantExprKind Kind)
Like evaluateAsRvalue(), but does no implicit lvalue-to-rvalue conversion.
Definition Context.cpp:102
bool evaluateAsInitializer(State &Parent, const VarDecl *VD, const Expr *Init, APValue &Result)
Evaluates a toplevel initializer.
Definition Context.cpp:131
void clear()
Clears the stack.
bool empty() const
Returns whether the stack is empty.
A pointer to a memory block, live or dead.
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
bool isDummy() const
Checks if the pointer points to a dummy value.
int64_t getIndex() const
Returns the index into an array.
bool isConst() const
Checks if an object or a subfield is mutable.
unsigned getNumElems() const
Returns the number of elements.
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
bool isLive() const
Checks if the pointer is live.
T & elem(unsigned I) const
Dereferences the element at index I.
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
size_t elemSize() const
Returns the element size of the innermost field.
const std::byte * getRawAddress() const
If backed by actual data (i.e.
The program contains and links the bytecode for all functions.
Structure/Class descriptor.
unsigned getNumBases() const
llvm::iterator_range< const_base_iter > bases() const
Interface for the VM to interact with the AST walker's context.
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)
Defines the clang::TargetInfo interface.
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
PrimType
Enumeration of the primitive types of the VM.
bool Init(InterpState &S, CodePtr OpPC)
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
bool Interpret(InterpState &S)
Interpreter entry point.
The JSON file list parser is used to communicate input to InstallAPI.
Expr::ConstantExprKind ConstantExprKind
bool isLambdaCallOperator(const CXXMethodDecl *MD)
@ Result
The result type of a method or function.
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Describes a memory block created by an allocation site.
unsigned getElemSize() const
returns the size of an element when the structure is viewed as an array.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
PrimType getPrimType() const