clang 21.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 "Function.h"
11#include "InterpFrame.h"
12#include "InterpShared.h"
13#include "InterpStack.h"
14#include "Opcode.h"
15#include "PrimType.h"
16#include "Program.h"
17#include "State.h"
20#include "clang/AST/DeclObjC.h"
21#include "clang/AST/Expr.h"
22#include "clang/AST/ExprCXX.h"
25#include "llvm/ADT/StringExtras.h"
26
27using namespace clang;
28using namespace clang::interp;
29
30static bool RetValue(InterpState &S, CodePtr &Pt) {
31 llvm::report_fatal_error("Interpreter cannot return values");
32}
33
34//===----------------------------------------------------------------------===//
35// Jmp, Jt, Jf
36//===----------------------------------------------------------------------===//
37
38static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
39 PC += Offset;
40 return true;
41}
42
43static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
44 if (S.Stk.pop<bool>()) {
45 PC += Offset;
46 }
47 return true;
48}
49
50static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
51 if (!S.Stk.pop<bool>()) {
52 PC += Offset;
53 }
54 return true;
55}
56
58 const ValueDecl *VD) {
59 const SourceInfo &E = S.Current->getSource(OpPC);
60 S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
61 S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
62}
63
65 const ValueDecl *VD);
67 const ValueDecl *D) {
68 const SourceInfo &E = S.Current->getSource(OpPC);
69
70 if (isa<ParmVarDecl>(D)) {
71 if (D->getType()->isReferenceType())
72 return false;
73
74 if (S.getLangOpts().CPlusPlus11) {
75 S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
76 S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
77 } else {
78 S.FFDiag(E);
79 }
80 return false;
81 }
82
83 if (!D->getType().isConstQualified()) {
85 } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
86 if (!VD->getAnyInitializer()) {
87 diagnoseMissingInitializer(S, OpPC, VD);
88 } else {
89 const SourceInfo &Loc = S.Current->getSource(OpPC);
90 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
91 S.Note(VD->getLocation(), diag::note_declared_at);
92 }
93 }
94
95 return false;
96}
97
99 const ValueDecl *VD) {
100 const SourceInfo &Loc = S.Current->getSource(OpPC);
101 if (!S.getLangOpts().CPlusPlus) {
102 S.FFDiag(Loc);
103 return;
104 }
105
106 if (const auto *VarD = dyn_cast<VarDecl>(VD);
107 VarD && VarD->getType().isConstQualified() &&
108 !VarD->getAnyInitializer()) {
109 diagnoseMissingInitializer(S, OpPC, VD);
110 return;
111 }
112
113 // Rather random, but this is to match the diagnostic output of the current
114 // interpreter.
115 if (isa<ObjCIvarDecl>(VD))
116 return;
117
119 S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
120 S.Note(VD->getLocation(), diag::note_declared_at);
121 return;
122 }
123
124 S.FFDiag(Loc,
125 S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
126 : diag::note_constexpr_ltor_non_integral,
127 1)
128 << VD << VD->getType();
129 S.Note(VD->getLocation(), diag::note_declared_at);
130}
131
132static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
133 AccessKinds AK) {
134 if (Ptr.isActive())
135 return true;
136
137 assert(Ptr.inUnion());
138 assert(Ptr.isField() && Ptr.getField());
139
140 Pointer U = Ptr.getBase();
141 Pointer C = Ptr;
142 while (!U.isRoot() && U.inUnion() && !U.isActive()) {
143 if (U.getField())
144 C = U;
145 U = U.getBase();
146 }
147 assert(C.isField());
148
149 // Get the inactive field descriptor.
150 const FieldDecl *InactiveField = C.getField();
151 assert(InactiveField);
152
153 // Consider:
154 // union U {
155 // struct {
156 // int x;
157 // int y;
158 // } a;
159 // }
160 //
161 // When activating x, we will also activate a. If we now try to read
162 // from y, we will get to CheckActive, because y is not active. In that
163 // case, our U will be a (not a union). We return here and let later code
164 // handle this.
165 if (!U.getFieldDesc()->isUnion())
166 return true;
167
168 // Find the active field of the union.
169 const Record *R = U.getRecord();
170 assert(R && R->isUnion() && "Not a union");
171
172 const FieldDecl *ActiveField = nullptr;
173 for (const Record::Field &F : R->fields()) {
174 const Pointer &Field = U.atField(F.Offset);
175 if (Field.isActive()) {
176 ActiveField = Field.getField();
177 break;
178 }
179 }
180
181 const SourceInfo &Loc = S.Current->getSource(OpPC);
182 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
183 << AK << InactiveField << !ActiveField << ActiveField;
184 return false;
185}
186
187static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
188 AccessKinds AK) {
189 if (auto ID = Ptr.getDeclID()) {
190 if (!Ptr.isStaticTemporary())
191 return true;
192
193 const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
194 Ptr.getDeclDesc()->asExpr());
195 if (!MTE)
196 return true;
197
198 // FIXME(perf): Since we do this check on every Load from a static
199 // temporary, it might make sense to cache the value of the
200 // isUsableInConstantExpressions call.
201 if (!MTE->isUsableInConstantExpressions(S.getASTContext()) &&
202 Ptr.block()->getEvalID() != S.Ctx.getEvalID()) {
203 const SourceInfo &E = S.Current->getSource(OpPC);
204 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
205 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
206 return false;
207 }
208 }
209 return true;
210}
211
212static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
213 if (auto ID = Ptr.getDeclID()) {
214 if (!Ptr.isStatic())
215 return true;
216
217 if (S.P.getCurrentDecl() == ID)
218 return true;
219
220 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
221 return false;
222 }
223 return true;
224}
225
226namespace clang {
227namespace interp {
228static void popArg(InterpState &S, const Expr *Arg) {
229 PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);
230 TYPE_SWITCH(Ty, S.Stk.discard<T>());
231}
232
234 const Function *Func) {
235 assert(S.Current);
236 assert(Func);
237
238 if (Func->isUnevaluatedBuiltin())
239 return;
240
241 // Some builtin functions require us to only look at the call site, since
242 // the classified parameter types do not match.
243 if (unsigned BID = Func->getBuiltinID();
245 const auto *CE =
246 cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
247 for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
248 const Expr *A = CE->getArg(I);
249 popArg(S, A);
250 }
251 return;
252 }
253
254 if (S.Current->Caller && Func->isVariadic()) {
255 // CallExpr we're look for is at the return PC of the current function, i.e.
256 // in the caller.
257 // This code path should be executed very rarely.
258 unsigned NumVarArgs;
259 const Expr *const *Args = nullptr;
260 unsigned NumArgs = 0;
261 const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());
262 if (const auto *CE = dyn_cast<CallExpr>(CallSite)) {
263 Args = CE->getArgs();
264 NumArgs = CE->getNumArgs();
265 } else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
266 Args = CE->getArgs();
267 NumArgs = CE->getNumArgs();
268 } else
269 assert(false && "Can't get arguments from that expression type");
270
271 assert(NumArgs >= Func->getNumWrittenParams());
272 NumVarArgs = NumArgs - (Func->getNumWrittenParams() +
273 isa<CXXOperatorCallExpr>(CallSite));
274 for (unsigned I = 0; I != NumVarArgs; ++I) {
275 const Expr *A = Args[NumArgs - 1 - I];
276 popArg(S, A);
277 }
278 }
279
280 // And in any case, remove the fixed parameters (the non-variadic ones)
281 // at the end.
282 for (PrimType Ty : Func->args_reverse())
283 TYPE_SWITCH(Ty, S.Stk.discard<T>());
284}
285
286bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
287 if (!Ptr.isExtern())
288 return true;
289
290 if (Ptr.isInitialized() ||
291 (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))
292 return true;
293
294 if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
295 const auto *VD = Ptr.getDeclDesc()->asValueDecl();
296 diagnoseNonConstVariable(S, OpPC, VD);
297 }
298 return false;
299}
300
301bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
302 if (!Ptr.isUnknownSizeArray())
303 return true;
304 const SourceInfo &E = S.Current->getSource(OpPC);
305 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
306 return false;
307}
308
309bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
310 AccessKinds AK) {
311 if (Ptr.isZero()) {
312 const auto &Src = S.Current->getSource(OpPC);
313
314 if (Ptr.isField())
315 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
316 else
317 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
318
319 return false;
320 }
321
322 if (!Ptr.isLive()) {
323 const auto &Src = S.Current->getSource(OpPC);
324
325 if (Ptr.isDynamic()) {
326 S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
327 } else if (!S.checkingPotentialConstantExpression()) {
328 bool IsTemp = Ptr.isTemporary();
329 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
330
331 if (IsTemp)
332 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
333 else
334 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
335 }
336
337 return false;
338 }
339
340 return true;
341}
342
343bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
344 assert(Desc);
345
346 const auto *D = Desc->asVarDecl();
347 if (!D || !D->hasGlobalStorage())
348 return true;
349
350 if (D == S.EvaluatingDecl)
351 return true;
352
353 if (D->isConstexpr())
354 return true;
355
356 // If we're evaluating the initializer for a constexpr variable in C23, we may
357 // only read other contexpr variables. Abort here since this one isn't
358 // constexpr.
359 if (const auto *VD = dyn_cast_if_present<VarDecl>(S.EvaluatingDecl);
360 VD && VD->isConstexpr() && S.getLangOpts().C23)
361 return Invalid(S, OpPC);
362
363 QualType T = D->getType();
364 bool IsConstant = T.isConstant(S.getASTContext());
366 if (!IsConstant) {
367 diagnoseNonConstVariable(S, OpPC, D);
368 return false;
369 }
370 return true;
371 }
372
373 if (IsConstant) {
374 if (S.getLangOpts().CPlusPlus) {
375 S.CCEDiag(S.Current->getLocation(OpPC),
376 S.getLangOpts().CPlusPlus11
377 ? diag::note_constexpr_ltor_non_constexpr
378 : diag::note_constexpr_ltor_non_integral,
379 1)
380 << D << T;
381 S.Note(D->getLocation(), diag::note_declared_at);
382 } else {
383 S.CCEDiag(S.Current->getLocation(OpPC));
384 }
385 return true;
386 }
387
390 !S.getLangOpts().CPlusPlus11) {
391 diagnoseNonConstVariable(S, OpPC, D);
392 return false;
393 }
394 return true;
395 }
396
397 diagnoseNonConstVariable(S, OpPC, D);
398 return false;
399}
400
401static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
402 if (!Ptr.isStatic() || !Ptr.isBlockPointer())
403 return true;
404 return CheckConstant(S, OpPC, Ptr.getDeclDesc());
405}
406
407bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
408 CheckSubobjectKind CSK) {
409 if (!Ptr.isZero())
410 return true;
411 const SourceInfo &Loc = S.Current->getSource(OpPC);
412 S.FFDiag(Loc, diag::note_constexpr_null_subobject)
413 << CSK << S.Current->getRange(OpPC);
414
415 return false;
416}
417
418bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
419 AccessKinds AK) {
420 if (!Ptr.isOnePastEnd())
421 return true;
422 if (S.getLangOpts().CPlusPlus) {
423 const SourceInfo &Loc = S.Current->getSource(OpPC);
424 S.FFDiag(Loc, diag::note_constexpr_access_past_end)
425 << AK << S.Current->getRange(OpPC);
426 }
427 return false;
428}
429
430bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
431 CheckSubobjectKind CSK) {
432 if (!Ptr.isElementPastEnd())
433 return true;
434 const SourceInfo &Loc = S.Current->getSource(OpPC);
435 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
436 << CSK << S.Current->getRange(OpPC);
437 return false;
438}
439
440bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
441 CheckSubobjectKind CSK) {
442 if (!Ptr.isOnePastEnd())
443 return true;
444
445 const SourceInfo &Loc = S.Current->getSource(OpPC);
446 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
447 << CSK << S.Current->getRange(OpPC);
448 return false;
449}
450
451bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
452 uint32_t Offset) {
453 uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();
454 uint32_t PtrOffset = Ptr.getByteOffset();
455
456 // We subtract Offset from PtrOffset. The result must be at least
457 // MinOffset.
458 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
459 return true;
460
461 const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
462 QualType TargetQT = E->getType()->getPointeeType();
463 QualType MostDerivedQT = Ptr.getDeclPtr().getType();
464
465 S.CCEDiag(E, diag::note_constexpr_invalid_downcast)
466 << MostDerivedQT << TargetQT;
467
468 return false;
469}
470
471bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
472 assert(Ptr.isLive() && "Pointer is not live");
473 if (!Ptr.isConst() || Ptr.isMutable())
474 return true;
475
476 // The This pointer is writable in constructors and destructors,
477 // even if isConst() returns true.
478 // TODO(perf): We could be hitting this code path quite a lot in complex
479 // constructors. Is there a better way to do this?
480 if (S.Current->getFunction()) {
481 for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
482 if (const Function *Func = Frame->getFunction();
483 Func && (Func->isConstructor() || Func->isDestructor()) &&
484 Ptr.block() == Frame->getThis().block()) {
485 return true;
486 }
487 }
488 }
489
490 if (!Ptr.isBlockPointer())
491 return false;
492
493 const QualType Ty = Ptr.getType();
494 const SourceInfo &Loc = S.Current->getSource(OpPC);
495 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
496 return false;
497}
498
499bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
500 assert(Ptr.isLive() && "Pointer is not live");
501 if (!Ptr.isMutable())
502 return true;
503
504 // In C++14 onwards, it is permitted to read a mutable member whose
505 // lifetime began within the evaluation.
506 if (S.getLangOpts().CPlusPlus14 &&
507 Ptr.block()->getEvalID() == S.Ctx.getEvalID())
508 return true;
509
510 const SourceInfo &Loc = S.Current->getSource(OpPC);
511 const FieldDecl *Field = Ptr.getField();
512 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
513 S.Note(Field->getLocation(), diag::note_declared_at);
514 return false;
515}
516
517static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
518 AccessKinds AK) {
519 assert(Ptr.isLive());
520
521 // FIXME: This check here might be kinda expensive. Maybe it would be better
522 // to have another field in InlineDescriptor for this?
523 if (!Ptr.isBlockPointer())
524 return true;
525
526 QualType PtrType = Ptr.getType();
527 if (!PtrType.isVolatileQualified())
528 return true;
529
530 const SourceInfo &Loc = S.Current->getSource(OpPC);
531 if (S.getLangOpts().CPlusPlus)
532 S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;
533 else
534 S.FFDiag(Loc);
535 return false;
536}
537
538bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
539 AccessKinds AK) {
540 assert(Ptr.isLive());
541
542 if (Ptr.isInitialized())
543 return true;
544
545 if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
546 VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
547 const SourceInfo &Loc = S.Current->getSource(OpPC);
548 if (VD->getAnyInitializer()) {
549 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
550 S.Note(VD->getLocation(), diag::note_declared_at);
551 } else {
552 diagnoseMissingInitializer(S, OpPC, VD);
553 }
554 return false;
555 }
556
557 if (!S.checkingPotentialConstantExpression()) {
558 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
559 << AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
560 }
561 return false;
562}
563
565 if (Ptr.isInitialized())
566 return true;
567
568 assert(S.getLangOpts().CPlusPlus);
569 const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());
570 if ((!VD->hasConstantInitialization() &&
571 VD->mightBeUsableInConstantExpressions(S.getASTContext())) ||
572 (S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&
573 !VD->hasICEInitializer(S.getASTContext()))) {
574 const SourceInfo &Loc = S.Current->getSource(OpPC);
575 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
576 S.Note(VD->getLocation(), diag::note_declared_at);
577 }
578 return false;
579}
580
581static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
582 if (!Ptr.isWeak())
583 return true;
584
585 const auto *VD = Ptr.getDeclDesc()->asVarDecl();
586 assert(VD);
587 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)
588 << VD;
589 S.Note(VD->getLocation(), diag::note_declared_at);
590
591 return false;
592}
593
594bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
595 AccessKinds AK) {
596 if (!CheckLive(S, OpPC, Ptr, AK))
597 return false;
598 if (!CheckConstant(S, OpPC, Ptr))
599 return false;
600 if (!CheckDummy(S, OpPC, Ptr, AK))
601 return false;
602 if (!CheckExtern(S, OpPC, Ptr))
603 return false;
604 if (!CheckRange(S, OpPC, Ptr, AK))
605 return false;
606 if (!CheckActive(S, OpPC, Ptr, AK))
607 return false;
608 if (!CheckInitialized(S, OpPC, Ptr, AK))
609 return false;
610 if (!CheckTemporary(S, OpPC, Ptr, AK))
611 return false;
612 if (!CheckWeak(S, OpPC, Ptr))
613 return false;
614 if (!CheckMutable(S, OpPC, Ptr))
615 return false;
616 if (!CheckVolatile(S, OpPC, Ptr, AK))
617 return false;
618 return true;
619}
620
621/// This is not used by any of the opcodes directly. It's used by
622/// EvalEmitter to do the final lvalue-to-rvalue conversion.
623bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
624 if (!CheckLive(S, OpPC, Ptr, AK_Read))
625 return false;
626 if (!CheckConstant(S, OpPC, Ptr))
627 return false;
628
629 if (!CheckDummy(S, OpPC, Ptr, AK_Read))
630 return false;
631 if (!CheckExtern(S, OpPC, Ptr))
632 return false;
633 if (!CheckRange(S, OpPC, Ptr, AK_Read))
634 return false;
635 if (!CheckActive(S, OpPC, Ptr, AK_Read))
636 return false;
637 if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
638 return false;
639 if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
640 return false;
641 if (!CheckWeak(S, OpPC, Ptr))
642 return false;
643 if (!CheckMutable(S, OpPC, Ptr))
644 return false;
645 return true;
646}
647
648bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
649 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
650 return false;
651 if (!CheckDummy(S, OpPC, Ptr, AK_Assign))
652 return false;
653 if (!CheckExtern(S, OpPC, Ptr))
654 return false;
655 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
656 return false;
657 if (!CheckGlobal(S, OpPC, Ptr))
658 return false;
659 if (!CheckConst(S, OpPC, Ptr))
660 return false;
661 return true;
662}
663
664bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
665 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
666 return false;
667 if (!Ptr.isDummy()) {
668 if (!CheckExtern(S, OpPC, Ptr))
669 return false;
670 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
671 return false;
672 }
673 return true;
674}
675
676bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
677 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
678 return false;
679 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
680 return false;
681 return true;
682}
683
684bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
685
686 if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
687 const SourceLocation &Loc = S.Current->getLocation(OpPC);
688 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
689 return false;
690 }
691
692 if (F->isConstexpr() && F->hasBody() &&
693 (F->getDecl()->isConstexpr() || F->getDecl()->hasAttr<MSConstexprAttr>()))
694 return true;
695
696 // Implicitly constexpr.
697 if (F->isLambdaStaticInvoker())
698 return true;
699
700 const SourceLocation &Loc = S.Current->getLocation(OpPC);
701 if (S.getLangOpts().CPlusPlus11) {
702 const FunctionDecl *DiagDecl = F->getDecl();
703
704 // Invalid decls have been diagnosed before.
705 if (DiagDecl->isInvalidDecl())
706 return false;
707
708 // If this function is not constexpr because it is an inherited
709 // non-constexpr constructor, diagnose that directly.
710 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
711 if (CD && CD->isInheritingConstructor()) {
712 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
713 if (!Inherited->isConstexpr())
714 DiagDecl = CD = Inherited;
715 }
716
717 // FIXME: If DiagDecl is an implicitly-declared special member function
718 // or an inheriting constructor, we should be much more explicit about why
719 // it's not constexpr.
720 if (CD && CD->isInheritingConstructor()) {
721 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
722 << CD->getInheritedConstructor().getConstructor()->getParent();
723 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
724 } else {
725 // Don't emit anything if the function isn't defined and we're checking
726 // for a constant expression. It might be defined at the point we're
727 // actually calling it.
728 bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
729 if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() &&
730 S.checkingPotentialConstantExpression())
731 return false;
732
733 // If the declaration is defined, declared 'constexpr' _and_ has a body,
734 // the below diagnostic doesn't add anything useful.
735 if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
736 DiagDecl->hasBody())
737 return false;
738
739 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
740 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
741
742 if (DiagDecl->getDefinition())
743 S.Note(DiagDecl->getDefinition()->getLocation(),
744 diag::note_declared_at);
745 else
746 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
747 }
748 } else {
749 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
750 }
751
752 return false;
753}
754
756 if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
757 S.FFDiag(S.Current->getSource(OpPC),
758 diag::note_constexpr_depth_limit_exceeded)
759 << S.getLangOpts().ConstexprCallDepth;
760 return false;
761 }
762
763 return true;
764}
765
766bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
767 if (!This.isZero())
768 return true;
769
770 const SourceInfo &Loc = S.Current->getSource(OpPC);
771
772 bool IsImplicit = false;
773 if (const auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.asExpr()))
774 IsImplicit = E->isImplicit();
775
776 if (S.getLangOpts().CPlusPlus11)
777 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
778 else
779 S.FFDiag(Loc);
780
781 return false;
782}
783
784bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
785 if (!MD->isPureVirtual())
786 return true;
787 const SourceInfo &E = S.Current->getSource(OpPC);
788 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
789 S.Note(MD->getLocation(), diag::note_declared_at);
790 return false;
791}
792
794 APFloat::opStatus Status, FPOptions FPO) {
795 // [expr.pre]p4:
796 // If during the evaluation of an expression, the result is not
797 // mathematically defined [...], the behavior is undefined.
798 // FIXME: C++ rules require us to not conform to IEEE 754 here.
799 if (Result.isNan()) {
800 const SourceInfo &E = S.Current->getSource(OpPC);
801 S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
802 << /*NaN=*/true << S.Current->getRange(OpPC);
803 return S.noteUndefinedBehavior();
804 }
805
806 // In a constant context, assume that any dynamic rounding mode or FP
807 // exception state matches the default floating-point environment.
808 if (S.inConstantContext())
809 return true;
810
811 if ((Status & APFloat::opInexact) &&
812 FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
813 // Inexact result means that it depends on rounding mode. If the requested
814 // mode is dynamic, the evaluation cannot be made in compile time.
815 const SourceInfo &E = S.Current->getSource(OpPC);
816 S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
817 return false;
818 }
819
820 if ((Status != APFloat::opOK) &&
821 (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
823 FPO.getAllowFEnvAccess())) {
824 const SourceInfo &E = S.Current->getSource(OpPC);
825 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
826 return false;
827 }
828
829 if ((Status & APFloat::opStatus::opInvalidOp) &&
831 const SourceInfo &E = S.Current->getSource(OpPC);
832 // There is no usefully definable result.
833 S.FFDiag(E);
834 return false;
835 }
836
837 return true;
838}
839
841 if (S.getLangOpts().CPlusPlus20)
842 return true;
843
844 const SourceInfo &E = S.Current->getSource(OpPC);
845 S.CCEDiag(E, diag::note_constexpr_new);
846 return true;
847}
848
850 DynamicAllocator::Form AllocForm,
851 DynamicAllocator::Form DeleteForm, const Descriptor *D,
852 const Expr *NewExpr) {
853 if (AllocForm == DeleteForm)
854 return true;
855
856 QualType TypeToDiagnose;
857 // We need to shuffle things around a bit here to get a better diagnostic,
858 // because the expression we allocated the block for was of type int*,
859 // but we want to get the array size right.
860 if (D->isArray()) {
861 QualType ElemQT = D->getType()->getPointeeType();
862 TypeToDiagnose = S.getASTContext().getConstantArrayType(
863 ElemQT, APInt(64, static_cast<uint64_t>(D->getNumElems()), false),
864 nullptr, ArraySizeModifier::Normal, 0);
865 } else
866 TypeToDiagnose = D->getType()->getPointeeType();
867
868 const SourceInfo &E = S.Current->getSource(OpPC);
869 S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
870 << static_cast<int>(DeleteForm) << static_cast<int>(AllocForm)
871 << TypeToDiagnose;
872 S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
873 << NewExpr->getSourceRange();
874 return false;
875}
876
877bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
878 const Pointer &Ptr) {
879 // Regular new type(...) call.
880 if (isa_and_nonnull<CXXNewExpr>(Source))
881 return true;
882 // operator new.
883 if (const auto *CE = dyn_cast_if_present<CallExpr>(Source);
884 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
885 return true;
886 // std::allocator.allocate() call
887 if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);
888 MCE && MCE->getMethodDecl()->getIdentifier()->isStr("allocate"))
889 return true;
890
891 // Whatever this is, we didn't heap allocate it.
892 const SourceInfo &Loc = S.Current->getSource(OpPC);
893 S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
895
896 if (Ptr.isTemporary())
897 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
898 else
899 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
900 return false;
901}
902
903/// We aleady know the given DeclRefExpr is invalid for some reason,
904/// now figure out why and print appropriate diagnostics.
905bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
906 const ValueDecl *D = DR->getDecl();
907 return diagnoseUnknownDecl(S, OpPC, D);
908}
909
910bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
911 AccessKinds AK) {
912 if (!Ptr.isDummy())
913 return true;
914
915 const Descriptor *Desc = Ptr.getDeclDesc();
916 const ValueDecl *D = Desc->asValueDecl();
917 if (!D)
918 return false;
919
920 if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)
921 return diagnoseUnknownDecl(S, OpPC, D);
922
923 assert(AK == AK_Assign);
924 if (S.getLangOpts().CPlusPlus14) {
925 const SourceInfo &E = S.Current->getSource(OpPC);
926 S.FFDiag(E, diag::note_constexpr_modify_global);
927 }
928 return false;
929}
930
932 const CallExpr *CE, unsigned ArgSize) {
933 auto Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());
934 auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);
935 unsigned Offset = 0;
936 unsigned Index = 0;
937 for (const Expr *Arg : Args) {
938 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
939 const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);
940 if (ArgPtr.isZero()) {
941 const SourceLocation &Loc = S.Current->getLocation(OpPC);
942 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
943 return false;
944 }
945 }
946
947 Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));
948 ++Index;
949 }
950 return true;
951}
952
953// FIXME: This is similar to code we already have in Compiler.cpp.
954// I think it makes sense to instead add the field and base destruction stuff
955// to the destructor Function itself. Then destroying a record would really
956// _just_ be calling its destructor. That would also help with the diagnostic
957// difference when the destructor or a field/base fails.
959 const Pointer &BasePtr,
960 const Descriptor *Desc) {
961 assert(Desc->isRecord());
962 const Record *R = Desc->ElemRecord;
963 assert(R);
964
965 if (Pointer::pointToSameBlock(BasePtr, S.Current->getThis())) {
966 const SourceInfo &Loc = S.Current->getSource(OpPC);
967 S.FFDiag(Loc, diag::note_constexpr_double_destroy);
968 return false;
969 }
970
971 // Destructor of this record.
972 if (const CXXDestructorDecl *Dtor = R->getDestructor();
973 Dtor && !Dtor->isTrivial()) {
974 const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
975 if (!DtorFunc)
976 return false;
977
978 S.Stk.push<Pointer>(BasePtr);
979 if (!Call(S, OpPC, DtorFunc, 0))
980 return false;
981 }
982 return true;
983}
984
985static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
986 assert(B);
987 const Descriptor *Desc = B->getDescriptor();
988
989 if (Desc->isPrimitive() || Desc->isPrimitiveArray())
990 return true;
991
992 assert(Desc->isRecord() || Desc->isCompositeArray());
993
994 if (Desc->isCompositeArray()) {
995 const Descriptor *ElemDesc = Desc->ElemDesc;
996 assert(ElemDesc->isRecord());
997
998 Pointer RP(const_cast<Block *>(B));
999 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
1000 if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc))
1001 return false;
1002 }
1003 return true;
1004 }
1005
1006 assert(Desc->isRecord());
1007 return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);
1008}
1009
1011 if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
1012 if (const CXXDestructorDecl *DD = RD->getDestructor())
1013 return DD->isVirtual();
1014 return false;
1015}
1016
1017bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
1018 bool IsGlobalDelete) {
1019 if (!CheckDynamicMemoryAllocation(S, OpPC))
1020 return false;
1021
1022 const Expr *Source = nullptr;
1023 const Block *BlockToDelete = nullptr;
1024 {
1025 // Extra scope for this so the block doesn't have this pointer
1026 // pointing to it when we destroy it.
1027 Pointer Ptr = S.Stk.pop<Pointer>();
1028
1029 // Deleteing nullptr is always fine.
1030 if (Ptr.isZero())
1031 return true;
1032
1033 // Remove base casts.
1034 QualType InitialType = Ptr.getType();
1035 while (Ptr.isBaseClass())
1036 Ptr = Ptr.getBase();
1037
1038 // For the non-array case, the types must match if the static type
1039 // does not have a virtual destructor.
1040 if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&
1041 !hasVirtualDestructor(InitialType)) {
1042 S.FFDiag(S.Current->getSource(OpPC),
1043 diag::note_constexpr_delete_base_nonvirt_dtor)
1044 << InitialType << Ptr.getType();
1045 return false;
1046 }
1047
1048 if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
1049 const SourceInfo &Loc = S.Current->getSource(OpPC);
1050 S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
1051 << Ptr.toDiagnosticString(S.getASTContext()) << Ptr.isOnePastEnd();
1052 return false;
1053 }
1054
1055 Source = Ptr.getDeclDesc()->asExpr();
1056 BlockToDelete = Ptr.block();
1057
1058 if (!CheckDeleteSource(S, OpPC, Source, Ptr))
1059 return false;
1060
1061 // For a class type with a virtual destructor, the selected operator delete
1062 // is the one looked up when building the destructor.
1063 QualType AllocType = Ptr.getType();
1064 if (!DeleteIsArrayForm && !IsGlobalDelete) {
1065 auto getVirtualOperatorDelete = [](QualType T) -> const FunctionDecl * {
1066 if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
1067 if (const CXXDestructorDecl *DD = RD->getDestructor())
1068 return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;
1069 return nullptr;
1070 };
1071
1072 if (const FunctionDecl *VirtualDelete =
1073 getVirtualOperatorDelete(AllocType);
1074 VirtualDelete &&
1075 !VirtualDelete->isReplaceableGlobalAllocationFunction()) {
1076 S.FFDiag(S.Current->getSource(OpPC),
1077 diag::note_constexpr_new_non_replaceable)
1078 << isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
1079 return false;
1080 }
1081 }
1082 }
1083 assert(Source);
1084 assert(BlockToDelete);
1085
1086 // Invoke destructors before deallocating the memory.
1087 if (!RunDestructors(S, OpPC, BlockToDelete))
1088 return false;
1089
1090 DynamicAllocator &Allocator = S.getAllocator();
1091 const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
1092 std::optional<DynamicAllocator::Form> AllocForm =
1093 Allocator.getAllocationForm(Source);
1094
1095 if (!Allocator.deallocate(Source, BlockToDelete, S)) {
1096 // Nothing has been deallocated, this must be a double-delete.
1097 const SourceInfo &Loc = S.Current->getSource(OpPC);
1098 S.FFDiag(Loc, diag::note_constexpr_double_delete);
1099 return false;
1100 }
1101
1102 assert(AllocForm);
1103 DynamicAllocator::Form DeleteForm = DeleteIsArrayForm
1106 return CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
1107 Source);
1108}
1109
1111 const APSInt &Value) {
1112 llvm::APInt Min;
1113 llvm::APInt Max;
1114
1115 if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())
1116 return;
1117
1118 ED->getValueRange(Max, Min);
1119 --Max;
1120
1121 if (ED->getNumNegativeBits() &&
1122 (Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {
1123 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1124 S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1125 << llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()
1126 << ED;
1127 } else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {
1128 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1129 S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1130 << llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()
1131 << ED;
1132 }
1133}
1134
1136 assert(T);
1137 assert(!S.getLangOpts().CPlusPlus23);
1138
1139 // C++1y: A constant initializer for an object o [...] may also invoke
1140 // constexpr constructors for o and its subobjects even if those objects
1141 // are of non-literal class types.
1142 //
1143 // C++11 missed this detail for aggregates, so classes like this:
1144 // struct foo_t { union { int i; volatile int j; } u; };
1145 // are not (obviously) initializable like so:
1146 // __attribute__((__require_constant_initialization__))
1147 // static const foo_t x = {{0}};
1148 // because "i" is a subobject with non-literal initialization (due to the
1149 // volatile member of the union). See:
1150 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
1151 // Therefore, we use the C++1y behavior.
1152
1153 if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&
1154 S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl) {
1155 return true;
1156 }
1157
1158 const Expr *E = S.Current->getExpr(OpPC);
1159 if (S.getLangOpts().CPlusPlus11)
1160 S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
1161 else
1162 S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
1163 return false;
1164}
1165
1166static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1167 uint32_t Off) {
1168 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1169 !CheckNull(S, OpPC, Ptr, CSK_Field))
1170 return false;
1171
1172 if (!CheckExtern(S, OpPC, Ptr))
1173 return false;
1174 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1175 return false;
1176 if (!CheckArray(S, OpPC, Ptr))
1177 return false;
1178 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1179 return false;
1180
1181 if (Ptr.isIntegralPointer()) {
1182 S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
1183 return true;
1184 }
1185
1186 if (!Ptr.isBlockPointer()) {
1187 // FIXME: The only time we (seem to) get here is when trying to access a
1188 // field of a typeid pointer. In that case, we're supposed to diagnose e.g.
1189 // `typeid(int).name`, but we currently diagnose `&typeid(int)`.
1190 S.FFDiag(S.Current->getSource(OpPC),
1191 diag::note_constexpr_access_unreadable_object)
1193 return false;
1194 }
1195
1196 if (Off > Ptr.block()->getSize())
1197 return false;
1198
1199 S.Stk.push<Pointer>(Ptr.atField(Off));
1200 return true;
1201}
1202
1203bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1204 const auto &Ptr = S.Stk.peek<Pointer>();
1205 return getField(S, OpPC, Ptr, Off);
1206}
1207
1208bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1209 const auto &Ptr = S.Stk.pop<Pointer>();
1210 return getField(S, OpPC, Ptr, Off);
1211}
1212
1213static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
1214 const Pointer &ThisPtr) {
1215 assert(Func->isConstructor());
1216
1217 const Descriptor *D = ThisPtr.getFieldDesc();
1218
1219 // FIXME: I think this case is not 100% correct. E.g. a pointer into a
1220 // subobject of a composite array.
1221 if (!D->ElemRecord)
1222 return true;
1223
1224 if (D->ElemRecord->getNumVirtualBases() == 0)
1225 return true;
1226
1227 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base)
1228 << Func->getParentDecl();
1229 return false;
1230}
1231
1233 uint32_t VarArgSize) {
1234 if (Func->hasThisPointer()) {
1235 size_t ArgSize = Func->getArgSize() + VarArgSize;
1236 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1237 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1238
1239 // If the current function is a lambda static invoker and
1240 // the function we're about to call is a lambda call operator,
1241 // skip the CheckInvoke, since the ThisPtr is a null pointer
1242 // anyway.
1243 if (!(S.Current->getFunction() &&
1244 S.Current->getFunction()->isLambdaStaticInvoker() &&
1245 Func->isLambdaCallOperator())) {
1246 if (!CheckInvoke(S, OpPC, ThisPtr))
1247 return false;
1248 }
1249
1250 if (S.checkingPotentialConstantExpression())
1251 return false;
1252 }
1253
1254 if (!CheckCallable(S, OpPC, Func))
1255 return false;
1256
1257 if (!CheckCallDepth(S, OpPC))
1258 return false;
1259
1260 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
1261 InterpFrame *FrameBefore = S.Current;
1262 S.Current = NewFrame.get();
1263
1264 // Note that we cannot assert(CallResult.hasValue()) here since
1265 // Ret() above only sets the APValue if the curent frame doesn't
1266 // have a caller set.
1267 if (Interpret(S)) {
1268 NewFrame.release(); // Frame was delete'd already.
1269 assert(S.Current == FrameBefore);
1270 return true;
1271 }
1272
1273 // Interpreting the function failed somehow. Reset to
1274 // previous state.
1275 S.Current = FrameBefore;
1276 return false;
1277}
1278
1279bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
1280 uint32_t VarArgSize) {
1281 assert(Func);
1282 auto cleanup = [&]() -> bool {
1284 return false;
1285 };
1286
1287 if (Func->hasThisPointer()) {
1288 size_t ArgSize = Func->getArgSize() + VarArgSize;
1289 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1290
1291 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1292
1293 // C++23 [expr.const]p5.6
1294 // an invocation of a virtual function ([class.virtual]) for an object whose
1295 // dynamic type is constexpr-unknown;
1296 if (ThisPtr.isDummy() && Func->isVirtual())
1297 return false;
1298
1299 // If the current function is a lambda static invoker and
1300 // the function we're about to call is a lambda call operator,
1301 // skip the CheckInvoke, since the ThisPtr is a null pointer
1302 // anyway.
1303 if (S.Current->getFunction() &&
1304 S.Current->getFunction()->isLambdaStaticInvoker() &&
1305 Func->isLambdaCallOperator()) {
1306 assert(ThisPtr.isZero());
1307 } else {
1308 if (!CheckInvoke(S, OpPC, ThisPtr))
1309 return cleanup();
1310 }
1311
1312 if (Func->isConstructor() && !checkConstructor(S, OpPC, Func, ThisPtr))
1313 return false;
1314 }
1315
1316 if (!CheckCallable(S, OpPC, Func))
1317 return cleanup();
1318
1319 // FIXME: The isConstructor() check here is not always right. The current
1320 // constant evaluator is somewhat inconsistent in when it allows a function
1321 // call when checking for a constant expression.
1322 if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&
1323 !Func->isConstructor())
1324 return cleanup();
1325
1326 if (!CheckCallDepth(S, OpPC))
1327 return cleanup();
1328
1329 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
1330 InterpFrame *FrameBefore = S.Current;
1331 S.Current = NewFrame.get();
1332
1333 InterpStateCCOverride CCOverride(S, Func->getDecl()->isImmediateFunction());
1334 // Note that we cannot assert(CallResult.hasValue()) here since
1335 // Ret() above only sets the APValue if the curent frame doesn't
1336 // have a caller set.
1337 if (Interpret(S)) {
1338 NewFrame.release(); // Frame was delete'd already.
1339 assert(S.Current == FrameBefore);
1340 return true;
1341 }
1342
1343 // Interpreting the function failed somehow. Reset to
1344 // previous state.
1345 S.Current = FrameBefore;
1346 return false;
1347}
1348
1350 uint32_t VarArgSize) {
1351 assert(Func->hasThisPointer());
1352 assert(Func->isVirtual());
1353 size_t ArgSize = Func->getArgSize() + VarArgSize;
1354 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1355 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1356
1357 const CXXRecordDecl *DynamicDecl = nullptr;
1358 {
1359 Pointer TypePtr = ThisPtr;
1360 while (TypePtr.isBaseClass())
1361 TypePtr = TypePtr.getBase();
1362
1363 QualType DynamicType = TypePtr.getType();
1364 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
1365 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
1366 else
1367 DynamicDecl = DynamicType->getAsCXXRecordDecl();
1368 }
1369 assert(DynamicDecl);
1370
1371 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
1372 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
1373 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
1374 DynamicDecl, StaticDecl, InitialFunction);
1375
1376 if (Overrider != InitialFunction) {
1377 // DR1872: An instantiated virtual constexpr function can't be called in a
1378 // constant expression (prior to C++20). We can still constant-fold such a
1379 // call.
1380 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
1381 const Expr *E = S.Current->getExpr(OpPC);
1382 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
1383 }
1384
1385 Func = S.getContext().getOrCreateFunction(Overrider);
1386
1387 const CXXRecordDecl *ThisFieldDecl =
1388 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
1389 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
1390 // If the function we call is further DOWN the hierarchy than the
1391 // FieldDesc of our pointer, just go up the hierarchy of this field
1392 // the furthest we can go.
1393 while (ThisPtr.isBaseClass())
1394 ThisPtr = ThisPtr.getBase();
1395 }
1396 }
1397
1398 if (!Call(S, OpPC, Func, VarArgSize))
1399 return false;
1400
1401 // Covariant return types. The return type of Overrider is a pointer
1402 // or reference to a class type.
1403 if (Overrider != InitialFunction &&
1404 Overrider->getReturnType()->isPointerOrReferenceType() &&
1405 InitialFunction->getReturnType()->isPointerOrReferenceType()) {
1406 QualType OverriderPointeeType =
1407 Overrider->getReturnType()->getPointeeType();
1408 QualType InitialPointeeType =
1409 InitialFunction->getReturnType()->getPointeeType();
1410 // We've called Overrider above, but calling code expects us to return what
1411 // InitialFunction returned. According to the rules for covariant return
1412 // types, what InitialFunction returns needs to be a base class of what
1413 // Overrider returns. So, we need to do an upcast here.
1414 unsigned Offset = S.getContext().collectBaseOffset(
1415 InitialPointeeType->getAsRecordDecl(),
1416 OverriderPointeeType->getAsRecordDecl());
1417 return GetPtrBasePop(S, OpPC, Offset);
1418 }
1419
1420 return true;
1421}
1422
1424 const CallExpr *CE, uint32_t BuiltinID) {
1425 // A little arbitrary, but the current interpreter allows evaluation
1426 // of builtin functions in this mode, with some exceptions.
1427 if (BuiltinID == Builtin::BI__builtin_operator_new &&
1428 S.checkingPotentialConstantExpression())
1429 return false;
1430 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
1431
1432 InterpFrame *FrameBefore = S.Current;
1433 S.Current = NewFrame.get();
1434
1435 if (InterpretBuiltin(S, OpPC, Func, CE, BuiltinID)) {
1436 // Release ownership of NewFrame to prevent it from being deleted.
1437 NewFrame.release(); // Frame was deleted already.
1438 // Ensure that S.Current is correctly reset to the previous frame.
1439 assert(S.Current == FrameBefore);
1440 return true;
1441 }
1442
1443 // Interpreting the function failed somehow. Reset to
1444 // previous state.
1445 S.Current = FrameBefore;
1446 return false;
1447}
1448
1449bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
1450 const CallExpr *CE) {
1451 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
1452
1453 const Function *F = FuncPtr.getFunction();
1454 if (!F) {
1455 const auto *E = cast<CallExpr>(S.Current->getExpr(OpPC));
1456 S.FFDiag(E, diag::note_constexpr_null_callee)
1457 << const_cast<Expr *>(E->getCallee()) << E->getSourceRange();
1458 return false;
1459 }
1460
1461 if (!FuncPtr.isValid() || !F->getDecl())
1462 return Invalid(S, OpPC);
1463
1464 assert(F);
1465
1466 // This happens when the call expression has been cast to
1467 // something else, but we don't support that.
1468 if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
1469 S.Ctx.classify(CE->getType()))
1470 return false;
1471
1472 // Check argument nullability state.
1473 if (F->hasNonNullAttr()) {
1474 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
1475 return false;
1476 }
1477
1478 assert(ArgSize >= F->getWrittenArgSize());
1479 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
1480
1481 // We need to do this explicitly here since we don't have the necessary
1482 // information to do it automatically.
1483 if (F->isThisPointerExplicit())
1484 VarArgSize -= align(primSize(PT_Ptr));
1485
1486 if (F->isVirtual())
1487 return CallVirt(S, OpPC, F, VarArgSize);
1488
1489 return Call(S, OpPC, F, VarArgSize);
1490}
1491
1493 std::optional<uint64_t> ArraySize) {
1494 const Pointer &Ptr = S.Stk.peek<Pointer>();
1495
1496 if (!CheckStore(S, OpPC, Ptr))
1497 return false;
1498
1499 if (!InvalidNewDeleteExpr(S, OpPC, E))
1500 return false;
1501
1502 const auto *NewExpr = cast<CXXNewExpr>(E);
1503 QualType StorageType = Ptr.getType();
1504
1505 if ((isa_and_nonnull<CXXNewExpr>(Ptr.getFieldDesc()->asExpr()) ||
1506 isa_and_nonnull<CXXMemberCallExpr>(Ptr.getFieldDesc()->asExpr())) &&
1507 StorageType->isPointerType()) {
1508 // FIXME: Are there other cases where this is a problem?
1509 StorageType = StorageType->getPointeeType();
1510 }
1511
1512 const ASTContext &ASTCtx = S.getASTContext();
1513 QualType AllocType;
1514 if (ArraySize) {
1515 AllocType = ASTCtx.getConstantArrayType(
1516 NewExpr->getAllocatedType(),
1517 APInt(64, static_cast<uint64_t>(*ArraySize), false), nullptr,
1519 } else {
1520 AllocType = NewExpr->getAllocatedType();
1521 }
1522
1523 unsigned StorageSize = 1;
1524 unsigned AllocSize = 1;
1525 if (const auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
1526 AllocSize = CAT->getZExtSize();
1527 if (const auto *CAT = dyn_cast<ConstantArrayType>(StorageType))
1528 StorageSize = CAT->getZExtSize();
1529
1530 if (AllocSize > StorageSize ||
1531 !ASTCtx.hasSimilarType(ASTCtx.getBaseElementType(AllocType),
1532 ASTCtx.getBaseElementType(StorageType))) {
1533 S.FFDiag(S.Current->getLocation(OpPC),
1534 diag::note_constexpr_placement_new_wrong_type)
1535 << StorageType << AllocType;
1536 return false;
1537 }
1538
1539 // Can't activate fields in a union, unless the direct base is the union.
1540 if (Ptr.inUnion() && !Ptr.isActive() && !Ptr.getBase().getRecord()->isUnion())
1541 return CheckActive(S, OpPC, Ptr, AK_Construct);
1542
1543 return true;
1544}
1545
1547 assert(E);
1548
1549 if (S.getLangOpts().CPlusPlus26)
1550 return true;
1551
1552 const auto &Loc = S.Current->getSource(OpPC);
1553
1554 if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
1555 const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
1556
1557 if (!S.getLangOpts().CPlusPlus26 && NewExpr->getNumPlacementArgs() > 0) {
1558 // This is allowed pre-C++26, but only an std function.
1559 if (S.Current->isStdFunction())
1560 return true;
1561 S.FFDiag(Loc, diag::note_constexpr_new_placement)
1562 << /*C++26 feature*/ 1 << E->getSourceRange();
1563 } else if (NewExpr->getNumPlacementArgs() == 1 &&
1564 !OperatorNew->isReservedGlobalPlacementOperator()) {
1565 S.FFDiag(Loc, diag::note_constexpr_new_placement)
1566 << /*Unsupported*/ 0 << E->getSourceRange();
1567 } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
1568 S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
1569 << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
1570 }
1571 } else {
1572 const auto *DeleteExpr = cast<CXXDeleteExpr>(E);
1573 const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
1574 if (!OperatorDelete->isReplaceableGlobalAllocationFunction()) {
1575 S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
1576 << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
1577 }
1578 }
1579
1580 return false;
1581}
1582
1584 const FixedPoint &FP) {
1585 const Expr *E = S.Current->getExpr(OpPC);
1586 if (S.checkingForUndefinedBehavior()) {
1588 E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
1589 << FP.toDiagnosticString(S.getASTContext()) << E->getType();
1590 }
1591 S.CCEDiag(E, diag::note_constexpr_overflow)
1592 << FP.toDiagnosticString(S.getASTContext()) << E->getType();
1593 return S.noteUndefinedBehavior();
1594}
1595
1596bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index) {
1597 const SourceInfo &Loc = S.Current->getSource(OpPC);
1598 S.FFDiag(Loc,
1599 diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)
1600 << Index;
1601 return false;
1602}
1603
1605 const Pointer &Ptr, unsigned BitWidth) {
1606 if (Ptr.isDummy())
1607 return false;
1608
1609 const SourceInfo &E = S.Current->getSource(OpPC);
1610 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1611 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1612
1613 if (Ptr.isBlockPointer() && !Ptr.isZero()) {
1614 // Only allow based lvalue casts if they are lossless.
1616 BitWidth)
1617 return Invalid(S, OpPC);
1618 }
1619 return true;
1620}
1621
1622bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1623 const Pointer &Ptr = S.Stk.pop<Pointer>();
1624
1625 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))
1626 return false;
1627
1628 S.Stk.push<IntegralAP<false>>(
1630 return true;
1631}
1632
1633bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1634 const Pointer &Ptr = S.Stk.pop<Pointer>();
1635
1636 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))
1637 return false;
1638
1639 S.Stk.push<IntegralAP<true>>(
1641 return true;
1642}
1643
1644bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
1645 bool TargetIsUCharOrByte) {
1646 // This is always fine.
1647 if (!HasIndeterminateBits)
1648 return true;
1649
1650 // Indeterminate bits can only be bitcast to unsigned char or std::byte.
1651 if (TargetIsUCharOrByte)
1652 return true;
1653
1654 const Expr *E = S.Current->getExpr(OpPC);
1655 QualType ExprType = E->getType();
1656 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
1657 << ExprType << S.getLangOpts().CharIsSigned << E->getSourceRange();
1658 return false;
1659}
1660
1661bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
1662 const Type *TypeInfoType) {
1663 S.Stk.push<Pointer>(TypePtr, TypeInfoType);
1664 return true;
1665}
1666
1667bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
1668 const auto &P = S.Stk.pop<Pointer>();
1669
1670 if (!P.isBlockPointer())
1671 return false;
1672
1673 S.Stk.push<Pointer>(P.getType().getTypePtr(), TypeInfoType);
1674 return true;
1675}
1676
1678 const auto *E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC));
1679 S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
1680 << E->getExprOperand()->getType()
1681 << E->getExprOperand()->getSourceRange();
1682 return false;
1683}
1684
1685// https://github.com/llvm/llvm-project/issues/102513
1686#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
1687#pragma optimize("", off)
1688#endif
1690 // The current stack frame when we started Interpret().
1691 // This is being used by the ops to determine wheter
1692 // to return from this function and thus terminate
1693 // interpretation.
1694 const InterpFrame *StartFrame = S.Current;
1695 assert(!S.Current->isRoot());
1696 CodePtr PC = S.Current->getPC();
1697
1698 // Empty program.
1699 if (!PC)
1700 return true;
1701
1702 for (;;) {
1703 auto Op = PC.read<Opcode>();
1704 CodePtr OpPC = PC;
1705
1706 switch (Op) {
1707#define GET_INTERP
1708#include "Opcodes.inc"
1709#undef GET_INTERP
1710 }
1711 }
1712}
1713// https://github.com/llvm/llvm-project/issues/102513
1714#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
1715#pragma optimize("", on)
1716#endif
1717
1718} // namespace interp
1719} // namespace clang
Defines the clang::ASTContext interface.
StringRef P
const Decl * D
Expr * E
Defines the clang::Expr interface and subclasses for C++ expressions.
static const FunctionDecl * getVirtualOperatorDelete(QualType T)
static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:38
static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:132
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.cpp:212
static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:187
static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:43
static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD)
Definition: Interp.cpp:98
static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, const ValueDecl *D)
Definition: Interp.cpp:66
static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:50
static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, const ValueDecl *VD)
Definition: Interp.cpp:57
static bool RetValue(InterpState &S, CodePtr &Pt)
Definition: Interp.cpp:30
static StringRef getIdentifier(const Token &Tok)
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:153
SourceLocation Loc
Definition: SemaObjC.cpp:759
#define bool
Definition: amdgpuintrin.h:20
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
Builtin::Context & BuiltinInfo
Definition: ASTContext.h:682
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
bool hasSimilarType(QualType T1, QualType T2) const
Determine if two types are similar, according to the C++ rules.
DiagnosticsEngine & getDiagnostics() const
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:799
bool hasCustomTypechecking(unsigned ID) const
Determines whether this builtin has custom typechecking.
Definition: Builtins.h:197
Represents a C++ destructor within a class.
Definition: DeclCXX.h:2856
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2117
bool isVirtual() const
Definition: DeclCXX.h:2172
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2874
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3055
Expr ** getArgs()
Retrieve the call arguments.
Definition: Expr.h:3058
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1265
ValueDecl * getDecl()
Definition: Expr.h:1333
bool isInvalidDecl() const
Definition: DeclBase.h:591
SourceLocation getLocation() const
Definition: DeclBase.h:442
bool hasAttr() const
Definition: DeclBase.h:580
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition: DeclBase.h:430
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1497
Represents an enum.
Definition: Decl.h:3868
unsigned getNumNegativeBits() const
Returns the width in bits required to store all the negative enumerators of this enum.
Definition: Decl.h:4065
void getValueRange(llvm::APInt &Max, llvm::APInt &Min) const
Calculates the [Min,Max) values the enum can store based on the NumPositiveBits and NumNegativeBits.
Definition: Decl.cpp:5014
This represents one expression.
Definition: Expr.h:110
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:276
QualType getType() const
Definition: Expr.h:142
LangOptions::FPExceptionModeKind getExceptionMode() const
Definition: LangOptions.h:925
RoundingMode getRoundingMode() const
Definition: LangOptions.h:913
Represents a member of a struct/union/class.
Definition: Decl.h:3040
Represents a function declaration or definition.
Definition: Decl.h:1935
QualType getReturnType() const
Definition: Decl.h:2727
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
Definition: Decl.h:2312
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition: Decl.h:2770
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
Definition: Decl.h:2405
bool isPureVirtual() const
Whether this virtual function is pure, i.e.
Definition: Decl.h:2288
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition: Decl.h:2217
bool isReplaceableGlobalAllocationFunction(std::optional< unsigned > *AlignmentParam=nullptr, bool *IsNothrow=nullptr) const
Determines whether this function is one of the replaceable global allocation functions: void *operato...
Definition: Decl.cpp:3384
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:3160
bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const
Returns true if the function has a definition that does not need to be instantiated.
Definition: Decl.cpp:3207
@ FPE_Ignore
Assume that floating-point exceptions are masked.
Definition: LangOptions.h:290
A (possibly-)qualified type.
Definition: Type.h:929
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
Definition: Type.h:8021
bool isConstant(const ASTContext &Ctx) const
Definition: Type.h:1089
ASTContext & getASTContext() const
Definition: Sema.h:534
const LangOptions & getLangOpts() const
Definition: Sema.h:527
Encodes a location in the source.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:334
uint64_t getPointerWidth(LangAS AddrSpace) const
Return the width of pointers on this target, for the specified address space.
Definition: TargetInfo.h:478
The base class of the type hierarchy.
Definition: Type.h:1828
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1916
bool isPointerType() const
Definition: Type.h:8192
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:738
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition: Type.h:8635
bool isPointerOrReferenceType() const
Definition: Type.h:8196
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1920
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:671
QualType getType() const
Definition: Decl.h:682
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
unsigned getSize() const
Returns the size of the block.
Definition: InterpBlock.h:80
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition: InterpBlock.h:68
unsigned getEvalID() const
The Evaluation ID this block was created in.
Definition: InterpBlock.h:87
Pointer into the code segment.
Definition: Source.h:30
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Definition: Source.h:60
Manages dynamic memory allocations done during bytecode interpretation.
Wrapper around fixed point types.
Definition: FixedPoint.h:23
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition: FixedPoint.h:81
Base class for stack frames, shared between VM and walker.
Definition: Frame.h:25
const Function * getFunction() const
Bytecode function.
Definition: Function.h:81
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition: Function.h:96
bool hasBody() const
Checks if the function already has a body attached.
Definition: Function.h:189
bool isVirtual() const
Checks if the function is virtual.
Definition: Function.cpp:48
bool isConstexpr() const
Checks if the function is valid to call in constexpr.
Definition: Function.h:141
bool isLambdaStaticInvoker() const
Returns whether this function is a lambda static invoker, which we generate custom byte code for.
Definition: Function.h:167
static IntegralAP from(T Value, unsigned NumBits=0)
Definition: IntegralAP.h:96
Frame storing local variables.
Definition: InterpFrame.h:26
Interpreter context.
Definition: InterpState.h:36
A pointer to a memory block, live or dead.
Definition: Pointer.h:88
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:195
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:346
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:507
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition: Pointer.h:522
bool inUnion() const
Definition: Pointer.h:419
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:161
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:560
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:501
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:549
bool isConst() const
Checks if an object or a subfield is mutable.
Definition: Pointer.h:571
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:180
bool isWeak() const
Definition: Pointer.h:539
bool isMutable() const
Checks if the field is mutable.
Definition: Pointer.h:533
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:432
bool isIntegralPointer() const
Definition: Pointer.h:483
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:351
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:438
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:282
bool isStaticTemporary() const
Checks if the storage is a static temporary.
Definition: Pointer.h:530
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:321
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:587
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:336
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:271
const IntPointer & asIntPointer() const
Definition: Pointer.h:473
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:454
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:296
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition: Pointer.cpp:491
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:623
uint64_t getIntegerRepresentation() const
Definition: Pointer.h:148
const FieldDecl * getField() const
Returns the field information.
Definition: Pointer.h:495
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:645
bool isBlockPointer() const
Definition: Pointer.h:482
bool isTemporary() const
Checks if the storage is temporary.
Definition: Pointer.h:514
SourceLocation getDeclLoc() const
Definition: Pointer.h:306
const Block * block() const
Definition: Pointer.h:602
Pointer getDeclPtr() const
Definition: Pointer.h:368
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:341
std::optional< unsigned > getDeclID() const
Returns the declaration ID.
Definition: Pointer.h:578
bool isBaseClass() const
Checks if a structure is a base class.
Definition: Pointer.h:555
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:288
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:488
Structure/Class descriptor.
Definition: Record.h:25
bool isUnion() const
Checks if the record is a union.
Definition: Record.h:57
const CXXDestructorDecl * getDestructor() const
Returns the destructor of the record, if any.
Definition: Record.h:73
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:80
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:77
Defines the clang::TargetInfo interface.
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.cpp:1208
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1598
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.cpp:1633
static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:517
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.cpp:1622
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:676
llvm::APInt APInt
Definition: FixedPoint.h:19
static bool runRecordDestructor(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const Descriptor *Desc)
Definition: Interp.cpp:958
bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType)
Definition: Interp.cpp:1667
bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Offset)
Checks if the dowcast using the given offset is possible with the given pointer.
Definition: Interp.cpp:451
bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, DynamicAllocator::Form AllocForm, DynamicAllocator::Form DeleteForm, const Descriptor *D, const Expr *NewExpr)
Diagnose mismatched new[]/delete or new/delete[] pairs.
Definition: Interp.cpp:849
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
We aleady know the given DeclRefExpr is invalid for some reason, now figure out why and print appropr...
Definition: Interp.cpp:905
bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
Definition: Interp.cpp:1661
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
Definition: Interp.cpp:755
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:766
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
Definition: Interp.cpp:343
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
Definition: Interp.cpp:1604
static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B)
Definition: Interp.cpp:985
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
Definition: Interp.cpp:1203
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:499
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition: Interp.cpp:440
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)
Definition: Interp.cpp:1583
static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Off)
Definition: Interp.cpp:1166
static bool hasVirtualDestructor(QualType T)
Definition: Interp.cpp:1010
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:594
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:538
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:131
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:418
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:784
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2387
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
Definition: Interp.cpp:840
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:309
bool DiagTypeid(InterpState &S, CodePtr OpPC)
Definition: Interp.cpp:1677
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
Definition: Interp.cpp:623
bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte)
Definition: Interp.cpp:1644
static void popArg(InterpState &S, const Expr *Arg)
Definition: Interp.cpp:228
static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, const Pointer &ThisPtr)
Definition: Interp.cpp:1213
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
Definition: Interp.cpp:1110
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:34
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:648
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:407
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, const Pointer &Ptr)
Check the source of the pointer passed to delete/delete[] has actually been heap allocated by us.
Definition: Interp.cpp:877
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status, FPOptions FPO)
Checks if the result of a floating-point operation is valid in the current context.
Definition: Interp.cpp:793
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.cpp:1232
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.cpp:1596
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, std::optional< uint64_t > ArraySize)
Check if the initializer and storage types of a placement-new expression match.
Definition: Interp.cpp:1492
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
Definition: Interp.cpp:1135
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:301
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
Definition: Interp.cpp:564
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
Checks if all the arguments annotated as 'nonnull' are in fact not null.
Definition: Interp.cpp:931
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is a dummy pointer.
Definition: Interp.cpp:910
static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.cpp:581
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.cpp:233
llvm::BitVector collectNonNullArgs(const FunctionDecl *F, const llvm::ArrayRef< const Expr * > &Args)
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:23
bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func, const CallExpr *CE, uint32_t BuiltinID)
Definition: Interp.cpp:1423
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
Definition: Interp.cpp:1017
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
Definition: Interp.cpp:1546
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call, uint32_t BuiltinID)
Interpret a builtin function.
llvm::APSInt APSInt
Definition: FixedPoint.h:20
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
Definition: Interp.cpp:286
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:684
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
Definition: Interp.cpp:1449
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.cpp:1349
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:471
bool Interpret(InterpState &S)
Interpreter entry point.
Definition: Interp.cpp:1689
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:664
The JSON file list parser is used to communicate input to InstallAPI.
@ SC_Extern
Definition: Specifiers.h:251
CheckSubobjectKind
The order of this enum is important for diagnostics.
Definition: State.h:41
@ CSK_Field
Definition: State.h:44
@ 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_Construct
Definition: State.h:35
@ AK_Increment
Definition: State.h:30
@ AK_Read
Definition: State.h:27
@ AK_Assign
Definition: State.h:29
@ AK_MemberCall
Definition: State.h:32
@ AK_Decrement
Definition: State.h:31
const FunctionProtoType * T
Describes a memory block created by an allocation site.
Definition: Descriptor.h:116
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:243
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition: Descriptor.h:257
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition: Descriptor.h:250
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:208
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition: Descriptor.h:148
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition: Descriptor.h:240
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:248
const VarDecl * asVarDecl() const
Definition: Descriptor.h:212
bool isRecord() const
Checks if the descriptor is of a record.
Definition: Descriptor.h:262
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition: Descriptor.h:146
const Expr * asExpr() const
Definition: Descriptor.h:205
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const
Definition: Pointer.cpp:681