clang 17.0.0git
Interp.cpp
Go to the documentation of this file.
1//===------- Interp.cpp - Interpreter for the constexpr VM ------*- 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#include "Interp.h"
10#include <limits>
11#include <vector>
12#include "Function.h"
13#include "InterpFrame.h"
14#include "InterpStack.h"
15#include "Opcode.h"
16#include "PrimType.h"
17#include "Program.h"
18#include "State.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/ExprCXX.h"
24#include "llvm/ADT/APSInt.h"
25
26using namespace clang;
27using namespace clang::interp;
28
29static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
30 llvm::report_fatal_error("Interpreter cannot return values");
31}
32
33//===----------------------------------------------------------------------===//
34// Jmp, Jt, Jf
35//===----------------------------------------------------------------------===//
36
37static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
38 PC += Offset;
39 return true;
40}
41
42static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
43 if (S.Stk.pop<bool>()) {
44 PC += Offset;
45 }
46 return true;
47}
48
49static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
50 if (!S.Stk.pop<bool>()) {
51 PC += Offset;
52 }
53 return true;
54}
55
56static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
57 AccessKinds AK) {
58 if (Ptr.isInitialized())
59 return true;
60 if (!S.checkingPotentialConstantExpression()) {
61 const SourceInfo &Loc = S.Current->getSource(OpPC);
62 S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
63 }
64 return false;
65}
66
67static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68 AccessKinds AK) {
69 if (Ptr.isActive())
70 return true;
71
72 // Get the inactive field descriptor.
73 const FieldDecl *InactiveField = Ptr.getField();
74
75 // Walk up the pointer chain to find the union which is not active.
76 Pointer U = Ptr.getBase();
77 while (!U.isActive()) {
78 U = U.getBase();
79 }
80
81 // Find the active field of the union.
82 Record *R = U.getRecord();
83 assert(R && R->isUnion() && "Not a union");
84 const FieldDecl *ActiveField = nullptr;
85 for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
86 const Pointer &Field = U.atField(R->getField(I)->Offset);
87 if (Field.isActive()) {
88 ActiveField = Field.getField();
89 break;
90 }
91 }
92
93 const SourceInfo &Loc = S.Current->getSource(OpPC);
94 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
95 << AK << InactiveField << !ActiveField << ActiveField;
96 return false;
97}
98
99static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
100 AccessKinds AK) {
101 if (auto ID = Ptr.getDeclID()) {
102 if (!Ptr.isStaticTemporary())
103 return true;
104
105 if (Ptr.getDeclDesc()->getType().isConstQualified())
106 return true;
107
108 if (S.P.getCurrentDecl() == ID)
109 return true;
110
111 const SourceInfo &E = S.Current->getSource(OpPC);
112 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
113 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
114 return false;
115 }
116 return true;
117}
118
119static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
120 if (auto ID = Ptr.getDeclID()) {
121 if (!Ptr.isStatic())
122 return true;
123
124 if (S.P.getCurrentDecl() == ID)
125 return true;
126
127 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
128 return false;
129 }
130 return true;
131}
132
133namespace clang {
134namespace interp {
135
136bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
137 if (!Ptr.isExtern())
138 return true;
139
140 if (!S.checkingPotentialConstantExpression()) {
141 auto *VD = Ptr.getDeclDesc()->asValueDecl();
142 const SourceInfo &Loc = S.Current->getSource(OpPC);
143 S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
144 S.Note(VD->getLocation(), diag::note_declared_at);
145 }
146 return false;
147}
148
149bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
150 if (!Ptr.isUnknownSizeArray())
151 return true;
152 const SourceInfo &E = S.Current->getSource(OpPC);
153 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
154 return false;
155}
156
157bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
158 AccessKinds AK) {
159 if (Ptr.isZero()) {
160 const auto &Src = S.Current->getSource(OpPC);
161
162 if (Ptr.isField())
163 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
164 else
165 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
166
167 return false;
168 }
169
170 if (!Ptr.isLive()) {
171 const auto &Src = S.Current->getSource(OpPC);
172 bool IsTemp = Ptr.isTemporary();
173
174 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
175
176 if (IsTemp)
177 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
178 else
179 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
180
181 return false;
182 }
183
184 return true;
185}
186
187bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
188 CheckSubobjectKind CSK) {
189 if (!Ptr.isZero())
190 return true;
191 const SourceInfo &Loc = S.Current->getSource(OpPC);
192 S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
193 return false;
194}
195
196bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
197 AccessKinds AK) {
198 if (!Ptr.isOnePastEnd())
199 return true;
200 const SourceInfo &Loc = S.Current->getSource(OpPC);
201 S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
202 return false;
203}
204
205bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
206 CheckSubobjectKind CSK) {
207 if (!Ptr.isElementPastEnd())
208 return true;
209 const SourceInfo &Loc = S.Current->getSource(OpPC);
210 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
211 return false;
212}
213
214bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
215 assert(Ptr.isLive() && "Pointer is not live");
216 if (!Ptr.isConst())
217 return true;
218
219 // The This pointer is writable in constructors and destructors,
220 // even if isConst() returns true.
221 if (const Function *Func = S.Current->getFunction();
222 Func && (Func->isConstructor() || Func->isDestructor()) &&
223 Ptr.block() == S.Current->getThis().block()) {
224 return true;
225 }
226
227 const QualType Ty = Ptr.getType();
228 const SourceInfo &Loc = S.Current->getSource(OpPC);
229 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
230 return false;
231}
232
233bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
234 assert(Ptr.isLive() && "Pointer is not live");
235 if (!Ptr.isMutable()) {
236 return true;
237 }
238
239 const SourceInfo &Loc = S.Current->getSource(OpPC);
240 const FieldDecl *Field = Ptr.getField();
241 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
242 S.Note(Field->getLocation(), diag::note_declared_at);
243 return false;
244}
245
246bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
247 if (!CheckLive(S, OpPC, Ptr, AK_Read))
248 return false;
249 if (!CheckExtern(S, OpPC, Ptr))
250 return false;
251 if (!CheckRange(S, OpPC, Ptr, AK_Read))
252 return false;
253 if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
254 return false;
255 if (!CheckActive(S, OpPC, Ptr, AK_Read))
256 return false;
257 if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
258 return false;
259 if (!CheckMutable(S, OpPC, Ptr))
260 return false;
261 return true;
262}
263
264bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
265 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
266 return false;
267 if (!CheckExtern(S, OpPC, Ptr))
268 return false;
269 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
270 return false;
271 if (!CheckGlobal(S, OpPC, Ptr))
272 return false;
273 if (!CheckConst(S, OpPC, Ptr))
274 return false;
275 return true;
276}
277
278bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
279 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
280 return false;
281 if (!CheckExtern(S, OpPC, Ptr))
282 return false;
283 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
284 return false;
285 return true;
286}
287
288bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
289 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
290 return false;
291 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
292 return false;
293 return true;
294}
295
296bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
297
298 if (F->isVirtual()) {
299 if (!S.getLangOpts().CPlusPlus20) {
300 const SourceLocation &Loc = S.Current->getLocation(OpPC);
301 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
302 return false;
303 }
304 }
305
306 if (!F->isConstexpr()) {
307 // Don't emit anything if we're checking for a potential constant
308 // expression. That will happen later when actually executing.
309 if (S.checkingPotentialConstantExpression())
310 return false;
311
312 const SourceLocation &Loc = S.Current->getLocation(OpPC);
313 if (S.getLangOpts().CPlusPlus11) {
314 const FunctionDecl *DiagDecl = F->getDecl();
315
316 // If this function is not constexpr because it is an inherited
317 // non-constexpr constructor, diagnose that directly.
318 auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
319 if (CD && CD->isInheritingConstructor()) {
320 auto *Inherited = CD->getInheritedConstructor().getConstructor();
321 if (!Inherited->isConstexpr())
322 DiagDecl = CD = Inherited;
323 }
324
325 // FIXME: If DiagDecl is an implicitly-declared special member function
326 // or an inheriting constructor, we should be much more explicit about why
327 // it's not constexpr.
328 if (CD && CD->isInheritingConstructor())
329 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
330 << CD->getInheritedConstructor().getConstructor()->getParent();
331 else
332 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
333 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
334 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
335 } else {
336 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
337 }
338 return false;
339 }
340
341 return true;
342}
343
344bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
345 if (!This.isZero())
346 return true;
347
348 const SourceInfo &Loc = S.Current->getSource(OpPC);
349
350 bool IsImplicit = false;
351 if (auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.asExpr()))
352 IsImplicit = E->isImplicit();
353
354 if (S.getLangOpts().CPlusPlus11)
355 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
356 else
357 S.FFDiag(Loc);
358
359 return false;
360}
361
362bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
363 if (!MD->isPure())
364 return true;
365 const SourceInfo &E = S.Current->getSource(OpPC);
366 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
367 S.Note(MD->getLocation(), diag::note_declared_at);
368 return false;
369}
370
372 const FieldDecl *SubObjDecl) {
373 assert(SubObjDecl && "Subobject declaration does not exist");
374 S.FFDiag(SI, diag::note_constexpr_uninitialized) << SubObjDecl;
375 S.Note(SubObjDecl->getLocation(),
376 diag::note_constexpr_subobject_declared_here);
377}
378
379static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
380 const Pointer &BasePtr, const Record *R);
381
383 const Pointer &BasePtr,
384 const ConstantArrayType *CAT) {
385 bool Result = true;
386 size_t NumElems = CAT->getSize().getZExtValue();
387 QualType ElemType = CAT->getElementType();
388
389 if (isa<RecordType>(ElemType.getTypePtr())) {
390 const Record *R = BasePtr.getElemRecord();
391 for (size_t I = 0; I != NumElems; ++I) {
392 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
393 Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R);
394 }
395 } else if (auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
396 for (size_t I = 0; I != NumElems; ++I) {
397 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
398 Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT);
399 }
400 } else {
401 for (size_t I = 0; I != NumElems; ++I) {
402 if (!BasePtr.atIndex(I).isInitialized()) {
403 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC),
404 BasePtr.getField());
405 Result = false;
406 }
407 }
408 }
409
410 return Result;
411}
412
414 const Pointer &BasePtr, const Record *R) {
415 assert(R);
416 bool Result = true;
417 // Check all fields of this record are initialized.
418 for (const Record::Field &F : R->fields()) {
419 Pointer FieldPtr = BasePtr.atField(F.Offset);
420 QualType FieldType = F.Decl->getType();
421
422 if (FieldType->isRecordType()) {
423 Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
424 } else if (FieldType->isArrayType()) {
425 const auto *CAT =
426 cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
427 Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT);
428 } else if (!FieldPtr.isInitialized()) {
429 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), F.Decl);
430 Result = false;
431 }
432 }
433
434 // Check Fields in all bases
435 for (const Record::Base &B : R->bases()) {
436 Pointer P = BasePtr.atField(B.Offset);
437 Result &= CheckFieldsInitialized(S, OpPC, P, B.R);
438 }
439
440 // TODO: Virtual bases
441
442 return Result;
443}
444
446 assert(!This.isZero());
447 const Record *R = This.getRecord();
448 return CheckFieldsInitialized(S, OpPC, This, R);
449}
450
451bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
452 // In a constant context, assume that any dynamic rounding mode or FP
453 // exception state matches the default floating-point environment.
454 if (S.inConstantContext())
455 return true;
456
457 const SourceInfo &E = S.Current->getSource(OpPC);
459
460 if ((Status & APFloat::opInexact) &&
461 FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
462 // Inexact result means that it depends on rounding mode. If the requested
463 // mode is dynamic, the evaluation cannot be made in compile time.
464 S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
465 return false;
466 }
467
468 if ((Status != APFloat::opOK) &&
469 (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
471 FPO.getAllowFEnvAccess())) {
472 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
473 return false;
474 }
475
476 if ((Status & APFloat::opStatus::opInvalidOp) &&
478 // There is no usefully definable result.
479 S.FFDiag(E);
480 return false;
481 }
482
483 return true;
484}
485
486bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
487 llvm::RoundingMode RM) {
488 Floating F = S.Stk.pop<Floating>();
489 Floating Result = F.toSemantics(Sem, RM);
490 S.Stk.push<Floating>(Result);
491 return true;
492}
493
495 // The current stack frame when we started Interpret().
496 // This is being used by the ops to determine wheter
497 // to return from this function and thus terminate
498 // interpretation.
499 const InterpFrame *StartFrame = S.Current;
500 assert(!S.Current->isRoot());
501 CodePtr PC = S.Current->getPC();
502
503 // Empty program.
504 if (!PC)
505 return true;
506
507 for (;;) {
508 auto Op = PC.read<Opcode>();
509 CodePtr OpPC = PC;
510
511 switch (Op) {
512#define GET_INTERP
513#include "Opcodes.inc"
514#undef GET_INTERP
515 }
516 }
517}
518
519} // namespace interp
520} // namespace clang
Defines the clang::ASTContext interface.
StringRef P
Defines the clang::Expr interface and subclasses for C++ expressions.
unsigned Offset
Definition: Format.cpp:2797
static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:37
static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:67
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.cpp:119
static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:99
static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:42
static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:56
static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result)
Definition: Interp.cpp:29
static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:49
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
QualType getElementType() const
Definition: Type.h:3064
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2035
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:3091
const llvm::APInt & getSize() const
Definition: Type.h:3112
SourceLocation getLocation() const
Definition: DeclBase.h:432
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const
Returns the set of floating point options that apply to this expression.
Definition: Expr.cpp:3811
LangOptions::FPExceptionModeKind getExceptionMode() const
Definition: LangOptions.h:754
RoundingMode getRoundingMode() const
Definition: LangOptions.h:742
Represents a member of a struct/union/class.
Definition: Decl.h:2945
Represents a function declaration or definition.
Definition: Decl.h:1917
bool isPure() const
Whether this virtual function is pure, i.e.
Definition: Decl.h:2255
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
Definition: Decl.h:2365
@ FPE_Ignore
Assume that floating-point exceptions are masked.
Definition: LangOptions.h:272
A (possibly-)qualified type.
Definition: Type.h:736
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:6664
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition: Type.h:6736
const LangOptions & getLangOpts() const
Definition: Sema.h:1654
Encodes a location in the source.
bool isArrayType() const
Definition: Type.h:6982
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition: Type.h:7483
bool isRecordType() const
Definition: Type.h:7006
Pointer into the code segment.
Definition: Source.h:26
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Definition: Source.h:50
Floating toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM) const
Definition: Floating.h:55
Bytecode function.
Definition: Function.h:74
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition: Function.h:89
bool isVirtual() const
Checks if the function is virtual.
Definition: Function.cpp:43
bool isConstexpr() const
Checks if the function is valid to call in constexpr.
Definition: Function.h:130
Frame storing local variables.
Definition: InterpFrame.h:29
Interpreter context.
Definition: InterpState.h:34
A pointer to a memory block, live or dead.
Definition: Pointer.h:61
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:99
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:148
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:260
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:258
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:81
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:273
bool isConst() const
Checks if an object or a subfield is mutable.
Definition: Pointer.h:278
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:93
bool isMutable() const
Checks if the field is mutable.
Definition: Pointer.h:267
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:237
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:201
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:165
bool isStaticTemporary() const
Checks if the storage is a static temporary.
Definition: Pointer.h:264
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:174
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:163
Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:170
Record * getElemRecord() const
Definition: Pointer.h:250
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:305
const FieldDecl * getField() const
Returns the field information.
Definition: Pointer.h:252
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:310
Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:248
bool isTemporary() const
Checks if the storage is temporary.
Definition: Pointer.h:262
SourceLocation getDeclLoc() const
Definition: Pointer.h:171
const Block * block() const
Definition: Pointer.h:293
std::optional< unsigned > getDeclID() const
Returns the declaration ID.
Definition: Pointer.h:283
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:167
Structure/Class descriptor.
Definition: Record.h:25
bool isUnion() const
Checks if the record is a union.
Definition: Record.h:55
const Field * getField(const FieldDecl *FD) const
Returns a field.
Definition: Record.cpp:30
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:85
unsigned getNumFields() const
Definition: Record.h:80
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:76
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:70
const Expr * asExpr() const
Definition: Source.cpp:25
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:288
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:494
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:344
bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks that all fields are initialized after a constructor call.
Definition: Interp.cpp:445
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:233
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:196
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:362
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1463
bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status)
Checks if the result is a floating-point operation is valid in the current context.
Definition: Interp.cpp:451
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:157
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:264
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:187
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.cpp:486
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:246
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:149
static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const Record *R)
Definition: Interp.cpp:413
static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI, const FieldDecl *SubObjDecl)
Definition: Interp.cpp:371
static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const ConstantArrayType *CAT)
Definition: Interp.cpp:382
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
Definition: Interp.cpp:136
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:296
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:214
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:278
CheckSubobjectKind
The order of this enum is important for diagnostics.
Definition: State.h:40
@ CSK_Field
Definition: State.h:43
@ Result
The result type of a method or function.
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
Definition: State.h:26
@ AK_Read
Definition: State.h:27
@ AK_Assign
Definition: State.h:29
@ AK_MemberCall
Definition: State.h:32
#define bool
Definition: stdbool.h:20
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:145
QualType getType() const
Definition: Descriptor.cpp:269
Describes a base class.
Definition: Record.h:35
Describes a record field.
Definition: Record.h:28