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