clang 24.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 "Compiler.h"
11#include "Function.h"
12#include "InterpFrame.h"
13#include "InterpShared.h"
14#include "InterpStack.h"
15#include "Opcode.h"
16#include "PrimType.h"
17#include "Program.h"
18#include "State.h"
21#include "clang/AST/DeclObjC.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/ExprCXX.h"
26#include "llvm/ADT/StringExtras.h"
27
28using namespace clang;
29using namespace clang::interp;
30
31#if __has_cpp_attribute(clang::musttail)
32#define MUSTTAIL [[clang::musttail]]
33#elif __has_cpp_attribute(msvc::musttail)
34#define MUSTTAIL [[msvc::musttail]]
35#elif __has_attribute(musttail)
36#define MUSTTAIL __attribute__((musttail))
37#endif
38
39// On MSVC, musttail does not guarantee tail calls in debug mode.
40// We disable it on MSVC generally since it doesn't seem to be able
41// to handle the way we use tailcalls.
42// PPC can't tail-call external calls, which is a problem for InterpNext.
43#if defined(_MSC_VER) || defined(__powerpc__) || !defined(MUSTTAIL) || \
44 defined(__i386__) || defined(__sparc__)
45#undef MUSTTAIL
46#define MUSTTAIL
47#define USE_TAILCALLS 0
48#else
49#define USE_TAILCALLS 1
50#endif
51
53 llvm::report_fatal_error("Interpreter cannot return values");
54}
55
56//===----------------------------------------------------------------------===//
57// Jmp, Jt, Jf
58//===----------------------------------------------------------------------===//
59
60static bool Jmp(InterpState &S, CodePtr OpPC, int32_t Offset) {
61 S.PC += Offset;
62 return S.noteStep(OpPC);
63}
64
65static bool Jt(InterpState &S, CodePtr OpPC, int32_t Offset) {
66 if (S.Stk.pop<bool>()) {
67 S.PC += Offset;
68 return S.noteStep(OpPC);
69 }
70 return true;
71}
72
73static bool Jf(InterpState &S, CodePtr OpPC, int32_t Offset) {
74 if (!S.Stk.pop<bool>()) {
75 S.PC += Offset;
76 return S.noteStep(OpPC);
77 }
78 return true;
79}
80
82 const ValueDecl *VD) {
83 const SourceInfo &E = S.Current->getSource(OpPC);
84 S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
85 S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
86}
87
88static void noteValueLocation(InterpState &S, const Block *B) {
89 const Descriptor *Desc = B->getDescriptor();
90
91 if (B->isDynamic())
92 S.Note(Desc->getLocation(), diag::note_constexpr_dynamic_alloc_here);
93 else if (B->isTemporary())
94 S.Note(Desc->getLocation(), diag::note_constexpr_temporary_here);
95 else
96 S.Note(Desc->getLocation(), diag::note_declared_at);
97}
98
100 const ValueDecl *VD,
101 AccessKinds AK = AK_Read);
103 const ValueDecl *D, AccessKinds AK = AK_Read) {
104 // This function tries pretty hard to produce a good diagnostic. Just skip
105 // that if nobody will see it anyway.
106 if (!S.diagnosing())
107 return false;
108
109 if (isa<ParmVarDecl>(D)) {
110 if (D->getType()->isReferenceType()) {
111 if (S.inConstantContext() && S.getLangOpts().CPlusPlus &&
112 !S.getLangOpts().CPlusPlus11) {
113 diagnoseNonConstVariable(S, OpPC, D);
114 return false;
115 }
116 }
117
118 const SourceInfo &Loc = S.Current->getSource(OpPC);
119 if (S.getLangOpts().CPlusPlus23 && D->getType()->isReferenceType()) {
120 S.FFDiag(Loc, diag::note_constexpr_access_unknown_variable, 1)
121 << AK_Read << D;
122 S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
123 } else if (S.getLangOpts().CPlusPlus11) {
124 S.FFDiag(Loc, diag::note_constexpr_function_param_value_unknown, 1) << D;
125 S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
126 } else {
127 S.FFDiag(Loc);
128 }
129 return false;
130 }
131
132 if (!D->getType().isConstQualified()) {
133 diagnoseNonConstVariable(S, OpPC, D, AK);
134 } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
135 if (!VD->getAnyInitializer()) {
136 diagnoseMissingInitializer(S, OpPC, VD);
137 } else {
138 const SourceInfo &Loc = S.Current->getSource(OpPC);
139 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
140 S.Note(VD->getLocation(), diag::note_declared_at);
141 }
142 }
143
144 return false;
145}
146
148 return AK == AK_Assign || AK == AK_Increment || AK == AK_Decrement ||
149 AK == AK_Construct || AK == AK_Destroy;
150}
151
153 const ValueDecl *VD, AccessKinds AK) {
154 if (!S.diagnosing())
155 return;
156
157 const SourceInfo &Loc = S.Current->getSource(OpPC);
158 if (!S.getLangOpts().CPlusPlus) {
159 S.FFDiag(Loc);
160 return;
161 }
162
163 if (const auto *VarD = dyn_cast<VarDecl>(VD);
164 VarD && VarD->getType().isConstQualified() &&
165 (VarD->isConstexpr() || !VarD->getType()->isArrayType()) &&
166 !VarD->getAnyInitializer()) {
167 diagnoseMissingInitializer(S, OpPC, VD);
168 return;
169 }
170
171 // Rather random, but this is to match the diagnostic output of the current
172 // interpreter.
173 if (isa<ObjCIvarDecl>(VD))
174 return;
175
177 if (isModification(AK)) {
178 S.FFDiag(Loc, diag::note_constexpr_modify_global);
179 } else {
180 S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
181 S.Note(VD->getLocation(), diag::note_declared_at);
182 }
183 return;
184 }
185
186 S.FFDiag(Loc,
187 S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
188 : diag::note_constexpr_ltor_non_integral,
189 1)
190 << VD << VD->getType();
191 S.Note(VD->getLocation(), diag::note_declared_at);
192}
193
194static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B,
195 AccessKinds AK) {
196 if (B->getDeclID()) {
197 if (!(B->isStatic() && B->isTemporary()))
198 return true;
199
200 const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
201 B->getDescriptor()->asExpr());
202 if (!MTE)
203 return true;
204
205 // FIXME(perf): Since we do this check on every Load from a static
206 // temporary, it might make sense to cache the value of the
207 // isUsableInConstantExpressions call.
209 (B->getEvalID() != S.EvalID &&
210 !MTE->isUsableInConstantExpressions(S.getASTContext()))) {
211 const SourceInfo &E = S.Current->getSource(OpPC);
212 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
213 noteValueLocation(S, B);
214 return false;
215 }
216 }
217
218 return true;
219}
220
221static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
222 if (auto ID = Ptr.getDeclID()) {
223 if (!Ptr.isStatic())
224 return true;
225
226 if (S.P.getCurrentDecl() == ID)
227 return true;
228
229 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
230 return false;
231 }
232 return true;
233}
234
235namespace clang {
236namespace interp {
237PRESERVE_NONE static bool BCP(InterpState &S, CodePtr OpPC, int32_t Offset,
238 PrimType PT);
239
241 const APSInt *Value, unsigned Bits) {
242 switch (Failure) {
244 assert(Value);
245 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_negative_shift)
246 << *Value;
247 break;
249 assert(Value);
250 const Expr *E = S.Current->getExpr(OpPC);
251 S.CCEDiag(E, diag::note_constexpr_large_shift)
252 << *Value << E->getType() << Bits;
253 break;
254 }
256 assert(Value);
257 S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_of_negative)
258 << *Value;
259 break;
261 S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
262 break;
263 }
264 return S.noteUndefinedBehavior();
265}
266
268 assert(S.Current);
269 assert(Func);
270
271 // Pop variadic parameter values from the stack.
272 if (S.Current->Caller && Func->isVariadic()) {
273 unsigned VariadicArgSize =
275 unsigned TargetStackSize = S.Stk.size() - VariadicArgSize;
276 while (S.Stk.size() != TargetStackSize) {
277 S.Stk.discardSlow();
278 }
279 }
280
281 // And in any case, remove the fixed parameters (the non-variadic ones)
282 // at the end.
283 for (const Function::ParamDescriptor &PDesc : Func->args_reverse())
284 TYPE_SWITCH(PDesc.T, S.Stk.discard<T>());
285
286 if (Func->hasImplicitThisPointer())
287 S.Stk.discard<Pointer>();
288 if (Func->hasRVO())
289 S.Stk.discard<Pointer>();
290}
291
292bool isConstexprUnknown(const Block *B) {
293 if (B->isDummy())
294 return isa_and_nonnull<ParmVarDecl>(B->getDescriptor()->asValueDecl());
296}
297
299 if (!P.isBlockPointer() || P.isZero())
300 return false;
301 return isConstexprUnknown(P.block());
302}
303
304bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {
305 if (Ptr.isDummy())
306 return false;
307 if (Ptr.isZero())
308 return true;
309 if (Ptr.isFunctionPointer())
310 return false;
311 if (Ptr.isIntegralPointer())
312 return true;
313 if (Ptr.isTypeidPointer())
314 return true;
315
316 if (Ptr.getType()->isAnyComplexType())
317 return true;
318
319 if (const Expr *Base = Ptr.getDeclDesc()->asExpr())
320 return isa<StringLiteral>(Base) && Ptr.getIndex() == 0;
321 return false;
322}
323
324bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
325 AccessKinds AK, bool WillActivate) {
326 if (Ptr.isActive())
327 return true;
328
329 assert(Ptr.inUnion());
330
331 // Find the outermost union.
332 PtrView U = Ptr.view().getBase();
333 PtrView C = Ptr.view();
334 while (!U.isRoot() && !U.isActive()) {
335 // A little arbitrary, but this is what the current interpreter does.
336 // See the AnonymousUnion test in test/AST/ByteCode/unions.cpp.
337 // GCC's output is more similar to what we would get without
338 // this condition.
339 if (U.getRecord() && U.getRecord()->isAnonymousUnion())
340 break;
341
342 C = U;
343 U = U.getBase();
344 }
345 assert(C.isField());
346 assert(C.getBase() == U);
347
348 // Consider:
349 // union U {
350 // struct {
351 // int x;
352 // int y;
353 // } a;
354 // }
355 //
356 // When activating x, we will also activate a. If we now try to read
357 // from y, we will get to CheckActive, because y is not active. In that
358 // case, our U will be a (not a union). We return here and let later code
359 // handle this.
360 if (!U.getFieldDesc()->isUnion())
361 return true;
362
363 // When we will activate Ptr, check that none of the unions in its path have a
364 // non-trivial default constructor.
365 if (WillActivate) {
366 bool Fails = false;
367 PtrView It = Ptr.view();
368 while (!It.isRoot() && !It.isActive()) {
369 if (const Record *R = It.getRecord(); R && R->isUnion()) {
370 if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(R->getDecl());
371 CXXRD && !CXXRD->hasTrivialDefaultConstructor()) {
372 Fails = true;
373 break;
374 }
375 }
376 It = It.getBase();
377 }
378 if (!Fails)
379 return true;
380 }
381
382 // Get the inactive field descriptor.
383 assert(!C.isActive());
384 const FieldDecl *InactiveField = C.getField();
385 assert(InactiveField);
386
387 // Find the active field of the union.
388 const Record *R = U.getRecord();
389 assert(R && R->isUnion() && "Not a union");
390
391 const FieldDecl *ActiveField = nullptr;
392 for (const Record::Field &F : R->fields()) {
393 PtrView Field = U.atField(F.Offset);
394 if (Field.isActive()) {
395 ActiveField = Field.getField();
396 break;
397 }
398 }
399
400 S.FFDiag(S.Current->getSource(OpPC),
401 diag::note_constexpr_access_inactive_union_member)
402 << AK << InactiveField << !ActiveField << ActiveField;
403 return false;
404}
405
406bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
407 if (!Ptr.isExtern())
408 return true;
409
410 if (!Ptr.isPastEnd() &&
411 (Ptr.isInitialized() ||
412 (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl)))
413 return true;
414
415 if (S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus &&
416 Ptr.isConst())
417 return false;
418
419 const auto *VD = Ptr.getDeclDesc()->asValueDecl();
421 diagnoseNonConstVariable(S, OpPC, VD);
422 return false;
423}
424
425bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
426 if (!Ptr.isUnknownSizeArray())
427 return true;
428 const SourceInfo &E = S.Current->getSource(OpPC);
429 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
430 return false;
431}
432
433bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
434 AccessKinds AK) {
435 if (Ptr.isZero()) {
436 const auto &Src = S.Current->getSource(OpPC);
437
438 if (Ptr.isField())
439 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
440 else
441 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
442
443 return false;
444 }
445
446 if (!Ptr.isLive()) {
447 const auto &Src = S.Current->getSource(OpPC);
448
449 if (Ptr.isDynamic()) {
450 S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
451 } else if (!S.checkingPotentialConstantExpression()) {
452 S.FFDiag(Src, diag::note_constexpr_access_uninit)
453 << AK << /*uninitialized=*/false << S.Current->getRange(OpPC);
454 noteValueLocation(S, Ptr.block());
455 }
456
457 return false;
458 }
459
460 return true;
461}
462
463bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc,
464 AccessKinds AK) {
465 assert(Desc);
466
467 const auto *D = Desc->asVarDecl();
469 // If we're checking for a constant destructor for this variable, we can
470 // only read from it if it is constant.
471 if (D->getType().isConstQualified())
472 return true;
473 } else if (!D || D == S.EvaluatingDecl || D->isConstexpr())
474 return true;
475
476 // If we're evaluating the initializer for a constexpr variable in C23, we may
477 // only read other contexpr variables. Abort here since this one isn't
478 // constexpr.
479 if (const auto *VD = S.EvaluatingDecl;
480 VD && VD->isConstexpr() && S.getLangOpts().C23)
481 return Invalid(S, OpPC);
482
483 QualType T = D->getType();
484 bool IsConstant = T.isConstant(S.getASTContext());
485 if (T->isIntegralOrEnumerationType()) {
486 if (!IsConstant) {
487 diagnoseNonConstVariable(S, OpPC, D, AK);
488 return false;
489 }
490 return true;
491 }
492
493 if (IsConstant) {
494 if (S.getLangOpts().CPlusPlus) {
495 S.CCEDiag(S.Current->getLocation(OpPC),
496 S.getLangOpts().CPlusPlus11
497 ? diag::note_constexpr_ltor_non_constexpr
498 : diag::note_constexpr_ltor_non_integral,
499 1)
500 << D << T;
501 S.Note(D->getLocation(), diag::note_declared_at);
502 } else {
503 S.CCEDiag(S.Current->getLocation(OpPC));
504 }
505 return true;
506 }
507
508 if (T->isPointerOrReferenceType()) {
509 if (!T->getPointeeType().isConstant(S.getASTContext()) ||
510 !S.getLangOpts().CPlusPlus11) {
511 diagnoseNonConstVariable(S, OpPC, D, AK);
512 return false;
513 }
514 return true;
515 }
516
517 diagnoseNonConstVariable(S, OpPC, D, AK);
518 return false;
519}
520
521static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
522 AccessKinds AK = AK_Read) {
524 return CheckConstant(S, OpPC, Ptr.getDeclDesc(), AK);
525
526 if (!Ptr.isStatic() || !Ptr.isBlockPointer())
527 return true;
528 if (!Ptr.getDeclID())
529 return true;
530 return CheckConstant(S, OpPC, Ptr.getDeclDesc(), AK);
531}
532
533bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
534 CheckSubobjectKind CSK) {
535 if (!Ptr.isZero())
536 return true;
537 const SourceInfo &Loc = S.Current->getSource(OpPC);
538 S.FFDiag(Loc, diag::note_constexpr_null_subobject)
539 << CSK << S.Current->getRange(OpPC);
540
541 return false;
542}
543
545 if (!Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray())
546 return true;
547 if (S.getLangOpts().CPlusPlus) {
548 const SourceInfo &Loc = S.Current->getSource(OpPC);
549 S.FFDiag(Loc, diag::note_constexpr_access_past_end)
550 << AK << S.Current->getRange(OpPC);
551 }
552 return false;
553}
554
555bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
556 CheckSubobjectKind CSK) {
557 if (!Ptr.isElementPastEnd() && !Ptr.isZeroSizeArray())
558 return true;
559 const SourceInfo &Loc = S.Current->getSource(OpPC);
560 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
561 << CSK << S.Current->getRange(OpPC);
562 return false;
563}
564
565bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
566 CheckSubobjectKind CSK) {
567 if (!Ptr.isOnePastEnd())
568 return true;
569
570 const SourceInfo &Loc = S.Current->getSource(OpPC);
571 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
572 << CSK << S.Current->getRange(OpPC);
573 return false;
574}
575
576bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
577 uint32_t Offset) {
578 uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();
579 uint32_t PtrOffset = Ptr.getByteOffset();
580
581 // We subtract Offset from PtrOffset. The result must be at least
582 // MinOffset.
583 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
584 return true;
585
586 const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
587 QualType ExprTy = E->getType();
588 if (ExprTy->isPointerOrReferenceType())
589 ExprTy = ExprTy->getPointeeType();
590
591 QualType TargetQT = ExprTy;
592 QualType MostDerivedQT = Ptr.getDeclPtr().getType();
593
594 if (MostDerivedQT->isPointerOrReferenceType())
595 MostDerivedQT = MostDerivedQT->getPointeeType();
596
597 S.CCEDiag(E, diag::note_constexpr_invalid_downcast)
598 << MostDerivedQT << TargetQT;
599
600 return false;
601}
602
603bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
604 assert(Ptr.isLive() && "Pointer is not live");
605 if (!Ptr.isConst())
606 return true;
607
608 if (Ptr.isMutable() && !Ptr.isConstInMutable())
609 return true;
610
611 if (!Ptr.isBlockPointer())
612 return false;
613
614 // The This pointer is writable in constructors and destructors,
615 // even if isConst() returns true.
616 for (PtrView V : llvm::reverse(S.InitializingPtrs)) {
617 if (V.block() != Ptr.block())
618 continue;
619 if (!V.getFieldDesc()->IsConst) {
620 // If the pointer being initialized is not declared as const,
621 // Ptr is const because of a parent of V, but that is irrelevant
622 // since V is being initialized and NOT const.
623 // This is fine, so return true.
624 return true;
625 }
626
627 // We know that Ptr is const because of a parent field and we also
628 // know that V is explicitly marked const.
629 // But since V is in InitializingPtrs, the fact that it is const doesn't
630 // matter and it is writable.
631 // What we now need to check is whether there is a pointer between Ptr and V
632 // that is marked const but NOT in InitializingPtrs. If that is the case,
633 // Ptr is currently not writable.
634 bool FoundProblem = false;
635 for (PtrView P = Ptr.view(); P != V; P = P.getBase()) {
636 if (P.getFieldDesc()->IsConst) {
637 FoundProblem = true;
638 break;
639 }
640 }
641
642 // We couldn't find any pointer that's explicitly marked const, so
643 // Ptr is writable right now.
644 if (!FoundProblem)
645 return true;
646 // We only need to find the right block once.
647 break;
648 }
649
651 QualType Ty = Ptr.getType();
652 if (!Ptr.getFieldDesc()->IsConst)
653 Ty.addConst();
654 const SourceInfo &Loc = S.Current->getSource(OpPC);
655 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
656 }
657 return false;
658}
659
661 assert(Ptr.isLive() && "Pointer is not live");
662 if (!Ptr.isMutable())
663 return true;
664
666 // Never allowed when checking for constant destruction.
667 // Diagnose below.
668 } else if (S.getLangOpts().CPlusPlus14 &&
670 // In C++14 onwards, it is permitted to read a mutable member whose
671 // lifetime began within the evaluation.
672 return true;
673 }
674
675 // Find the reason this pointer is mutable.
676 PtrView MutablePtr = Ptr;
677 while (!MutablePtr.isRoot() && MutablePtr.getBase().isMutable())
678 MutablePtr = MutablePtr.getBase();
679
680 const SourceInfo &Loc = S.Current->getSource(OpPC);
681 const FieldDecl *Field = MutablePtr.getField();
682 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK << Field;
683 S.Note(Field->getLocation(), diag::note_declared_at);
684 return false;
685}
686
687static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
688 AccessKinds AK) {
689 assert(Ptr.isLive());
690
691 if (!Ptr.isVolatile())
692 return true;
693
694 if (!S.getLangOpts().CPlusPlus)
695 return Invalid(S, OpPC);
696
697 // Volatile object can be written-to and read if they are being constructed.
698 if (S.initializingBlock(Ptr.block()))
699 return true;
700
701 // The reason why Ptr is volatile might be further up the hierarchy.
702 // Find that pointer.
703 Pointer P = Ptr;
704 while (!P.isRoot()) {
706 break;
707 P = P.getBase();
708 }
709
710 const NamedDecl *ND = nullptr;
711 int DiagKind;
712 SourceLocation Loc;
713 if (const auto *F = P.getField()) {
714 DiagKind = 2;
715 Loc = F->getLocation();
716 ND = F;
717 } else if (auto *VD = P.getFieldDesc()->asValueDecl()) {
718 DiagKind = 1;
719 Loc = VD->getLocation();
720 ND = VD;
721 } else {
722 DiagKind = 0;
723 if (const auto *E = P.getFieldDesc()->asExpr())
724 Loc = E->getExprLoc();
725 }
726
727 S.FFDiag(S.Current->getLocation(OpPC),
728 diag::note_constexpr_access_volatile_obj, 1)
729 << AK << DiagKind << ND;
730 S.Note(Loc, diag::note_constexpr_volatile_here) << DiagKind;
731 return false;
732}
733
735 AccessKinds AK) {
736 assert(Ptr.isLive());
737 assert(!Ptr.isInitialized());
738 return diagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.block(),
739 Ptr.getLifetime(), AK);
740}
741
742bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
743 const Block *B, Lifetime LT, AccessKinds AK) {
745 // Extern and static member declarations might be initialized later.
746 if (Extern)
747 return false;
748
749 if (const VarDecl *VD = B->getDescriptor()->asVarDecl();
750 VD && VD->isStaticDataMember())
751 return false;
752 }
753
754 const Descriptor *Desc = B->getDescriptor();
755
756 if (const auto *VD = Desc->asVarDecl();
757 VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
758
759 if (VD == S.EvaluatingDecl &&
760 !(S.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType())) {
761 if (!S.getLangOpts().CPlusPlus14 &&
762 !VD->getType().isConstant(S.getASTContext())) {
763 // Diagnose as non-const read.
764 diagnoseNonConstVariable(S, OpPC, VD);
765 } else {
766 // Diagnose as "read of object outside its lifetime".
767 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
768 << AK << /*IsIndeterminate=*/false;
769 S.Note(VD->getFirstDecl()->getLocation(), diag::note_declared_at);
770 }
771 return false;
772 }
773
774 if (VD->getAnyInitializer()) {
775 const SourceInfo &Loc = S.Current->getSource(OpPC);
776 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
777 S.Note(VD->getLocation(), diag::note_declared_at);
778 } else {
779 diagnoseMissingInitializer(S, OpPC, VD);
780 }
781 return false;
782 }
783
785 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
786 << AK << /*uninitialized=*/(LT == Lifetime::Started)
787 << S.Current->getRange(OpPC);
788 noteValueLocation(S, B);
789 }
790 return false;
791}
792
794 const Block *B, AccessKinds AK) {
795 if (LT == Lifetime::Started)
796 return true;
797
799 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
800 << AK << /*uninitialized=*/false << S.Current->getRange(OpPC);
801 noteValueLocation(S, B);
802 }
803 return false;
804}
805static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
806 AccessKinds AK) {
807 return CheckLifetime(S, OpPC, Ptr.getLifetime(), Ptr.block(), AK);
808}
809
810static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B) {
811 if (!B->isWeak())
812 return true;
813
814 const auto *VD = B->getDescriptor()->asVarDecl();
815 assert(VD);
816 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)
817 << VD;
818 S.Note(VD->getLocation(), diag::note_declared_at);
819
820 return false;
821}
822
823// The list of checks here is just the one from CheckLoad, but with the
824// ones removed that are impossible on primitive global values.
825// For example, since those can't be members of structs, they also can't
826// be mutable.
827bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
828 const auto &Desc = B->getBlockDesc<GlobalInlineDescriptor>();
829 if (!B->isAccessible()) {
830 if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B))))
831 return false;
832 if (!CheckDummy(S, OpPC, B, AK_Read))
833 return false;
834 return CheckWeak(S, OpPC, B);
835 }
836
837 if (!CheckConstant(S, OpPC, B->getDescriptor()))
838 return false;
839 if (Desc.InitState != GlobalInitState::Initialized)
840 return diagnoseUninitialized(S, OpPC, B->isExtern(), B);
841 if (!CheckTemporary(S, OpPC, B, AK_Read))
842 return false;
843 if (B->getDescriptor()->IsVolatile) {
844 if (!S.getLangOpts().CPlusPlus)
845 return Invalid(S, OpPC);
846
847 const ValueDecl *D = B->getDescriptor()->asValueDecl();
848 S.FFDiag(S.Current->getLocation(OpPC),
849 diag::note_constexpr_access_volatile_obj, 1)
850 << AK_Read << 1 << D;
851 S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;
852 return false;
853 }
854 return true;
855}
856
857// Similarly, for local loads.
858bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
859 assert(!B->isExtern());
860 const auto &Desc = *reinterpret_cast<const InlineDescriptor *>(B->rawData());
861 const Descriptor *BlockDesc = B->getDescriptor();
862 if (!Desc.IsInitialized)
863 return diagnoseUninitialized(S, OpPC, /*Extern=*/false, B, Desc.LifeState);
864 if (!CheckLifetime(S, OpPC, Desc.LifeState, B, AK_Read))
865 return false;
866 if (BlockDesc->IsVolatile) {
867 if (!S.getLangOpts().CPlusPlus)
868 return Invalid(S, OpPC);
869
870 const ValueDecl *D = BlockDesc->asValueDecl();
871 S.FFDiag(S.Current->getLocation(OpPC),
872 diag::note_constexpr_access_volatile_obj, 1)
873 << AK_Read << 1 << D;
874 S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;
875 return false;
876 }
877
878 // A non-const local variable while we don't have a parent frame. This must be
879 // a local variable in a statement expression.
880 if (S.Current->isBottomFrame() && !BlockDesc->IsConst &&
882 if (const ValueDecl *VD = BlockDesc->asValueDecl())
883 diagnoseNonConstVariable(S, OpPC, VD);
884 return false;
885 }
886 return true;
887}
888
889bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
890 AccessKinds AK) {
891 if (Ptr.isZero()) {
892 const auto &Src = S.Current->getSource(OpPC);
893
894 if (Ptr.isField())
895 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
896 else
897 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
898 return false;
899 }
900 // Block pointers are the only ones we can actually read from.
901 if (!Ptr.isBlockPointer())
902 return false;
903
904 if (!Ptr.block()->isAccessible()) {
905 if (!CheckLive(S, OpPC, Ptr, AK))
906 return false;
907 if (!CheckExtern(S, OpPC, Ptr))
908 return false;
909 if (!CheckDummy(S, OpPC, Ptr.block(), AK))
910 return false;
911 return CheckWeak(S, OpPC, Ptr.block());
912 }
913
914 if (!CheckConstant(S, OpPC, Ptr, AK))
915 return false;
916 if (!CheckRange(S, OpPC, Ptr, AK))
917 return false;
918 if (!CheckActive(S, OpPC, Ptr, AK))
919 return false;
920 if (!Ptr.isInitialized())
921 return diagnoseUninitialized(S, OpPC, Ptr, AK);
922 if (!CheckLifetime(S, OpPC, Ptr, AK))
923 return false;
924 if (!CheckTemporary(S, OpPC, Ptr.block(), AK))
925 return false;
926
927 if (!CheckMutable(S, OpPC, Ptr))
928 return false;
929 if (!CheckVolatile(S, OpPC, Ptr, AK))
930 return false;
931 if (isConstexprUnknown(Ptr))
932 return false;
933
934 if (!Ptr.isArrayRoot()) {
935 // According to GCC info page:
936 //
937 // 6.28 Compound Literals
938 //
939 // As an optimization, G++ sometimes gives array compound literals
940 // longer lifetimes: when the array either appears outside a function or
941 // has a const-qualified type. If foo and its initializer had elements
942 // of type char *const rather than char *, or if foo were a global
943 // variable, the array would have static storage duration. But it is
944 // probably safest just to avoid the use of array compound literals in
945 // C++ code.
946 //
947 // Obey that rule by checking constness for converted array types.
948 const Descriptor *Desc = Ptr.getFieldDesc();
949 if (const auto *CLE =
950 dyn_cast_if_present<CompoundLiteralExpr>(Desc->asExpr())) {
951 if (QualType CLETy = CLE->getType();
952 CLETy->isArrayType() && !CLETy.isConstant(S.getASTContext())) {
953 S.FFDiag(S.Current->getLocation(OpPC),
954 diag::note_invalid_subexpr_in_const_expr)
955 << S.Current->getRange(OpPC);
956 S.Note(CLE->getExprLoc(), diag::note_declared_at);
957 return false;
958 }
959 }
960 }
961 return true;
962}
963
964/// This is not used by any of the opcodes directly. It's used by
965/// EvalEmitter to do the final lvalue-to-rvalue conversion.
966bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
967 assert(!Ptr.isZero());
968 if (!Ptr.isBlockPointer())
969 return false;
970
971 if (!Ptr.block()->isAccessible()) {
972 if (!CheckLive(S, OpPC, Ptr, AK_Read))
973 return false;
974 if (!CheckExtern(S, OpPC, Ptr))
975 return false;
976 if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read))
977 return false;
978 return CheckWeak(S, OpPC, Ptr.block());
979 }
980
981 if (!CheckConstant(S, OpPC, Ptr))
982 return false;
983
984 if (!CheckActive(S, OpPC, Ptr, AK_Read))
985 return false;
986 if (!CheckLifetime(S, OpPC, Ptr, AK_Read))
987 return false;
988 if (!Ptr.isInitialized())
989 return diagnoseUninitialized(S, OpPC, Ptr, AK_Read);
990 if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Read))
991 return false;
992 if (!CheckMutable(S, OpPC, Ptr))
993 return false;
994 if (Ptr.isConstexprUnknown())
995 return false;
996 return true;
997}
998
999bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1000 bool WillBeActivated) {
1001 if (!Ptr.isBlockPointer() || Ptr.isZero())
1002 return false;
1003
1004 if (!Ptr.block()->isAccessible()) {
1005 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
1006 return false;
1007 if (!CheckExtern(S, OpPC, Ptr))
1008 return false;
1009 return CheckDummy(S, OpPC, Ptr.block(), AK_Assign);
1010 }
1011 if (!WillBeActivated && !CheckLifetime(S, OpPC, Ptr, AK_Assign))
1012 return false;
1013 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
1014 return false;
1015 if (!CheckActive(S, OpPC, Ptr, AK_Assign, WillBeActivated))
1016 return false;
1017 if (!CheckGlobal(S, OpPC, Ptr))
1018 return false;
1019 if (!CheckConst(S, OpPC, Ptr))
1020 return false;
1021 if (!CheckVolatile(S, OpPC, Ptr, AK_Assign))
1022 return false;
1023 if (!CheckMutable(S, OpPC, Ptr, AK_Assign))
1024 return false;
1025 if (isConstexprUnknown(Ptr))
1026 return false;
1027 return true;
1028}
1029
1030static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1031 bool IsCtor, bool IsDtor) {
1032 if (!Ptr.isDummy() && !isConstexprUnknown(Ptr)) {
1033 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
1034 return false;
1035 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
1036 return false;
1037 if (!(IsCtor || IsDtor) && !CheckLifetime(S, OpPC, Ptr, AK_MemberCall))
1038 return false;
1039 }
1040 return true;
1041}
1042
1043bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
1044 if (!CheckLive(S, OpPC, Ptr, AK_Assign))
1045 return false;
1046 if (!CheckRange(S, OpPC, Ptr, AK_Assign))
1047 return false;
1048 return true;
1049}
1050
1052 const FunctionDecl *DiagDecl) {
1053 // Bail out if the function declaration itself is invalid. We will
1054 // have produced a relevant diagnostic while parsing it, so just
1055 // note the problematic sub-expression.
1056 if (DiagDecl->isInvalidDecl())
1057 return Invalid(S, OpPC);
1058
1059 // Diagnose failed assertions specially.
1060 if (S.Current->getLocation(OpPC).isMacroID() && DiagDecl->getIdentifier()) {
1061 // FIXME: Instead of checking for an implementation-defined function,
1062 // check and evaluate the assert() macro.
1063 StringRef Name = DiagDecl->getName();
1064 bool AssertFailed =
1065 Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert";
1066 if (AssertFailed) {
1067 S.FFDiag(S.Current->getLocation(OpPC),
1068 diag::note_constexpr_assert_failed);
1069 return false;
1070 }
1071 }
1072
1073 if (!S.getLangOpts().CPlusPlus11) {
1074 S.FFDiag(S.Current->getLocation(OpPC),
1075 diag::note_invalid_subexpr_in_const_expr);
1076 return false;
1077 }
1078
1079 // If this function is not constexpr because it is an inherited
1080 // non-constexpr constructor, diagnose that directly.
1081 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
1082 if (CD && CD->isInheritingConstructor()) {
1083 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
1084 if (!Inherited->isConstexpr())
1085 DiagDecl = CD = Inherited;
1086 }
1087
1088 // Silently reject constructors of invalid classes. The invalid class
1089 // has been rejected elsewhere before.
1090 if (CD && CD->getParent()->isInvalidDecl())
1091 return false;
1092
1093 // FIXME: If DiagDecl is an implicitly-declared special member function
1094 // or an inheriting constructor, we should be much more explicit about why
1095 // it's not constexpr.
1096 if (CD && CD->isInheritingConstructor()) {
1097 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_invalid_inhctor,
1098 1)
1099 << CD->getInheritedConstructor().getConstructor()->getParent();
1100 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
1101 } else {
1102 // Don't emit anything if the function isn't defined and we're checking
1103 // for a constant expression. It might be defined at the point we're
1104 // actually calling it.
1105 bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
1106 bool IsDefined = DiagDecl->isDefined();
1107 if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&
1109 return false;
1110
1111 // If the declaration is defined, declared 'constexpr' _and_ has a body,
1112 // the below diagnostic doesn't add anything useful.
1113 if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && DiagDecl->hasBody())
1114 return false;
1115
1116 S.FFDiag(S.Current->getLocation(OpPC),
1117 diag::note_constexpr_invalid_function, 1)
1118 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
1119
1120 const FunctionDecl *Definition;
1121 bool HasBody = DiagDecl->hasBody(Definition);
1122 if (HasBody && Definition)
1123 S.Note(Definition->getLocation(), diag::note_declared_at);
1124 else
1125 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
1126 }
1127
1128 return false;
1129}
1130
1131static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
1132 if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
1133 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1134 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
1135 return false;
1136 }
1137
1138 if (F->isValid() && F->hasBody() &&
1140 F->getDecl()->hasAttr<MSConstexprAttr>())))
1141 return true;
1142
1143 const FunctionDecl *DiagDecl = F->getDecl();
1144 const FunctionDecl *Definition = nullptr;
1145 DiagDecl->hasBody(Definition);
1146
1148 DiagDecl->isConstexpr()) {
1149 return false;
1150 }
1151
1152 return diagnoseCallableDecl(S, OpPC, DiagDecl);
1153}
1154
1155static bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
1156 if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
1157 S.FFDiag(S.Current->getSource(OpPC),
1158 diag::note_constexpr_depth_limit_exceeded)
1159 << S.getLangOpts().ConstexprCallDepth;
1160 return false;
1161 }
1162
1163 return true;
1164}
1165
1167 if (S.Current->hasThisPointer())
1168 return true;
1169
1170 const Expr *E = S.Current->getExpr(OpPC);
1171 if (S.getLangOpts().CPlusPlus11) {
1172 bool IsImplicit = false;
1173 if (const auto *TE = dyn_cast<CXXThisExpr>(E))
1174 IsImplicit = TE->isImplicit();
1175 S.FFDiag(E, diag::note_constexpr_this) << IsImplicit;
1176 } else {
1177 S.FFDiag(E);
1178 }
1179
1180 return false;
1181}
1182
1183bool CheckFloatStatus(InterpState &S, CodePtr OpPC, APFloat::opStatus Status,
1184 FPOptions FPO) {
1185 // In a constant context, assume that any dynamic rounding mode or FP
1186 // exception state matches the default floating-point environment.
1187 if (S.inConstantContext())
1188 return true;
1189
1190 if ((Status & APFloat::opInexact) &&
1191 FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
1192 // Inexact result means that it depends on rounding mode. If the requested
1193 // mode is dynamic, the evaluation cannot be made in compile time.
1194 const SourceInfo &E = S.Current->getSource(OpPC);
1195 S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
1196 return false;
1197 }
1198
1199 if ((Status != APFloat::opOK) &&
1200 (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
1202 FPO.getAllowFEnvAccess())) {
1203 const SourceInfo &E = S.Current->getSource(OpPC);
1204 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
1205 return false;
1206 }
1207
1208 if ((Status & APFloat::opStatus::opInvalidOp) &&
1210 const SourceInfo &E = S.Current->getSource(OpPC);
1211 // There is no usefully definable result.
1212 S.FFDiag(E);
1213 return false;
1214 }
1215
1216 return true;
1217}
1218
1220 APFloat::opStatus Status, FPOptions FPO) {
1221 // FIXME: The standard quote below is deleted by P3899R3.
1222 // [expr.pre]p4:
1223 // If during the evaluation of an expression, the result is not
1224 // mathematically defined [...], the behavior is undefined.
1225 // FIXME: C++ rules require us to not conform to IEEE 754 here.
1226 // FIXME: The NaN check should not be applied outside of "constant contexts"
1227 // because it prevents NaN propagation and the "invalid" status is the
1228 // responsibility of CheckFloatStatus.
1229 if (Result.isNan()) {
1230 const SourceInfo &E = S.Current->getSource(OpPC);
1231 S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
1232 << /*NaN=*/true << S.Current->getRange(OpPC);
1233 return S.noteUndefinedBehavior();
1234 }
1235
1236 return CheckFloatStatus(S, OpPC, Status, FPO);
1237}
1238
1240 if (S.getLangOpts().CPlusPlus20)
1241 return true;
1242
1243 const SourceInfo &E = S.Current->getSource(OpPC);
1244 S.CCEDiag(E, diag::note_constexpr_new);
1245 return true;
1246}
1247
1249 DynamicAllocator::Form AllocForm,
1250 DynamicAllocator::Form DeleteForm, const Descriptor *D,
1251 const Expr *NewExpr) {
1252 if (AllocForm == DeleteForm)
1253 return true;
1254
1255 QualType TypeToDiagnose = D->getDataType(S.getASTContext());
1256
1257 const SourceInfo &E = S.Current->getSource(OpPC);
1258 S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
1259 << static_cast<int>(DeleteForm) << static_cast<int>(AllocForm)
1260 << TypeToDiagnose;
1261 S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
1262 << NewExpr->getSourceRange();
1263 return false;
1264}
1265
1266bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
1267 const Pointer &Ptr) {
1268 // Regular new type(...) call.
1269 if (isa_and_nonnull<CXXNewExpr>(Source))
1270 return true;
1271 // operator new.
1272 if (const auto *CE = dyn_cast_if_present<CallExpr>(Source);
1273 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
1274 return true;
1275 // std::allocator.allocate() call
1276 if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);
1277 MCE && MCE->getMethodDecl()->getIdentifier()->isStr("allocate"))
1278 return true;
1279
1280 // Whatever this is, we didn't heap allocate it.
1281 const SourceInfo &Loc = S.Current->getSource(OpPC);
1282 S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
1284 noteValueLocation(S, Ptr.block());
1285 return false;
1286}
1287
1288/// We aleady know the given DeclRefExpr is invalid for some reason,
1289/// now figure out why and print appropriate diagnostics.
1290bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
1291 const ValueDecl *D = DR->getDecl();
1292 return diagnoseUnknownDecl(S, OpPC, D);
1293}
1294
1296 bool InitializerFailed) {
1297 assert(DR);
1298
1299 if (InitializerFailed) {
1300 const SourceInfo &Loc = S.Current->getSource(OpPC);
1301 const auto *VD = cast<VarDecl>(DR->getDecl());
1302 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
1303 S.Note(VD->getLocation(), diag::note_declared_at);
1304 return false;
1305 }
1306
1307 return CheckDeclRef(S, OpPC, DR);
1308}
1309
1310bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {
1311 if (!B->isDummy())
1312 return true;
1313
1314 const ValueDecl *D = B->getDescriptor()->asValueDecl();
1315 if (!D)
1316 return false;
1317
1318 if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)
1319 return diagnoseUnknownDecl(S, OpPC, D, AK);
1320
1321 if (AK == AK_Destroy || S.getLangOpts().CPlusPlus14) {
1322 const SourceInfo &E = S.Current->getSource(OpPC);
1323 S.FFDiag(E, diag::note_constexpr_modify_global);
1324 }
1325 return false;
1326}
1327
1328static bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
1329 const CallExpr *CE, unsigned ArgSize) {
1330 auto Args = ArrayRef(CE->getArgs(), CE->getNumArgs());
1331 auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);
1332 unsigned Offset = 0;
1333 unsigned Index = 0;
1334 for (const Expr *Arg : Args) {
1335 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
1336 const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);
1337 if (ArgPtr.isZero()) {
1338 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1339 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
1340 return false;
1341 }
1342 }
1343
1344 Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));
1345 ++Index;
1346 }
1347 return true;
1348}
1349
1351 const Pointer &BasePtr,
1352 const Descriptor *Desc) {
1353 assert(Desc->isRecord());
1354 const Record *R = Desc->ElemRecord;
1355 assert(R);
1356
1357 if (!S.Current->isBottomFrame() && S.Current->hasThisPointer() &&
1359 Pointer::pointToSameBlock(BasePtr, S.Current->getThis())) {
1360 const SourceInfo &Loc = S.Current->getSource(OpPC);
1361 S.FFDiag(Loc, diag::note_constexpr_double_destroy);
1362 return false;
1363 }
1364
1365 // Destructor of this record.
1366 const CXXDestructorDecl *Dtor = R->getDestructor();
1367 assert(Dtor);
1368 assert(!Dtor->isTrivial());
1369 const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
1370 if (!DtorFunc)
1371 return false;
1372
1373 S.Stk.push<Pointer>(BasePtr);
1374 return Call(S, OpPC, DtorFunc, 0);
1375}
1376
1377static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
1378 assert(B);
1379 const Descriptor *Desc = B->getDescriptor();
1380
1381 if (Desc->isPrimitive() || Desc->isPrimitiveArray())
1382 return true;
1383
1384 assert(Desc->isRecord() || Desc->isCompositeArray());
1385
1386 if (Desc->hasTrivialDtor())
1387 return true;
1388
1389 if (Desc->isCompositeArray()) {
1390 unsigned N = Desc->getNumElems();
1391 if (N == 0)
1392 return true;
1393 const Descriptor *ElemDesc = Desc->ElemDesc;
1394 assert(ElemDesc->isRecord());
1395
1396 Pointer RP(const_cast<Block *>(B));
1397 for (int I = static_cast<int>(N) - 1; I >= 0; --I) {
1398 if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc))
1399 return false;
1400 }
1401 return true;
1402 }
1403
1404 assert(Desc->isRecord());
1405 return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);
1406}
1407
1409 if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
1410 if (const CXXDestructorDecl *DD = RD->getDestructor())
1411 return DD->isVirtual();
1412 return false;
1413}
1414
1415bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
1416 bool IsGlobalDelete) {
1417 if (!CheckDynamicMemoryAllocation(S, OpPC))
1418 return false;
1419
1420 DynamicAllocator &Allocator = S.getAllocator();
1421
1422 const Expr *Source = nullptr;
1423 const Block *BlockToDelete = nullptr;
1424 {
1425 // Extra scope for this so the block doesn't have this pointer
1426 // pointing to it when we destroy it.
1427 Pointer Ptr = S.Stk.pop<Pointer>();
1428
1429 // Deleteing nullptr is always fine.
1430 if (Ptr.isZero())
1431 return true;
1432
1433 if (!Ptr.isBlockPointer())
1434 return false;
1435
1436 // Remove base casts.
1437 QualType InitialType = Ptr.getType();
1438 Ptr = Ptr.expand().stripBaseCasts();
1439
1440 Source = Ptr.getDeclDesc()->asExpr();
1441 BlockToDelete = Ptr.block();
1442
1443 // Check that new[]/delete[] or new/delete were used, not a mixture.
1444 const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
1445 if (std::optional<DynamicAllocator::Form> AllocForm =
1446 Allocator.getAllocationForm(Source)) {
1447 DynamicAllocator::Form DeleteForm =
1448 DeleteIsArrayForm ? DynamicAllocator::Form::Array
1450 if (!CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
1451 Source))
1452 return false;
1453 }
1454
1455 // For the non-array case, the types must match if the static type
1456 // does not have a virtual destructor.
1457 if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&
1458 !hasVirtualDestructor(InitialType)) {
1459 S.FFDiag(S.Current->getSource(OpPC),
1460 diag::note_constexpr_delete_base_nonvirt_dtor)
1461 << InitialType << Ptr.getType();
1462 return false;
1463 }
1464
1465 if (!Ptr.isRoot() || (Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray()) ||
1466 (Ptr.isArrayElement() && Ptr.getIndex() != 0)) {
1467 const SourceInfo &Loc = S.Current->getSource(OpPC);
1468 S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
1469 << Ptr.toDiagnosticString(S.getASTContext()) << Ptr.isOnePastEnd();
1470 return false;
1471 }
1472
1473 if (!CheckDeleteSource(S, OpPC, Source, Ptr))
1474 return false;
1475
1476 // For a class type with a virtual destructor, the selected operator delete
1477 // is the one looked up when building the destructor.
1478 if (!DeleteIsArrayForm && !IsGlobalDelete) {
1479 QualType AllocType = Ptr.getType();
1480 auto getVirtualOperatorDelete = [](QualType T) -> const FunctionDecl * {
1481 if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
1482 if (const CXXDestructorDecl *DD = RD->getDestructor())
1483 return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;
1484 return nullptr;
1485 };
1486
1487 if (const FunctionDecl *VirtualDelete =
1488 getVirtualOperatorDelete(AllocType);
1489 VirtualDelete &&
1490 !VirtualDelete
1492 S.FFDiag(S.Current->getSource(OpPC),
1493 diag::note_constexpr_new_non_replaceable)
1494 << isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
1495 return false;
1496 }
1497 }
1498 }
1499 assert(Source);
1500 assert(BlockToDelete);
1501
1502 // Invoke destructors before deallocating the memory.
1503 if (!RunDestructors(S, OpPC, BlockToDelete))
1504 return false;
1505
1506 if (!Allocator.deallocate(Source, BlockToDelete)) {
1507 // Nothing has been deallocated, this must be a double-delete.
1508 const SourceInfo &Loc = S.Current->getSource(OpPC);
1509 S.FFDiag(Loc, diag::note_constexpr_double_delete);
1510 return false;
1511 }
1512
1513 return true;
1514}
1515
1517 const APSInt &Value) {
1518 llvm::APInt Min;
1519 llvm::APInt Max;
1520 ED->getValueRange(Max, Min);
1521 --Max;
1522
1523 if (ED->getNumNegativeBits() &&
1524 (Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {
1525 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1526 S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1527 << llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()
1528 << ED;
1529 } else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {
1530 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1531 S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1532 << llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()
1533 << ED;
1534 }
1535}
1536
1538 assert(T);
1539 assert(!S.getLangOpts().CPlusPlus23);
1540
1541 // C++1y: A constant initializer for an object o [...] may also invoke
1542 // constexpr constructors for o and its subobjects even if those objects
1543 // are of non-literal class types.
1544 //
1545 // C++11 missed this detail for aggregates, so classes like this:
1546 // struct foo_t { union { int i; volatile int j; } u; };
1547 // are not (obviously) initializable like so:
1548 // __attribute__((__require_constant_initialization__))
1549 // static const foo_t x = {{0}};
1550 // because "i" is a subobject with non-literal initialization (due to the
1551 // volatile member of the union). See:
1552 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
1553 // Therefore, we use the C++1y behavior.
1554
1555 if (!S.Current->isBottomFrame() &&
1558 return true;
1559 }
1560
1561 const Expr *E = S.Current->getExpr(OpPC);
1562 if (S.getLangOpts().CPlusPlus11)
1563 S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
1564 else
1565 S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
1566 return false;
1567}
1568
1570 const Pointer &Ptr, unsigned Offset) {
1571 assert(Ptr.isTypeidPointer());
1572 const Record *R = S.getContext().getRecord(
1574 if (!R)
1575 return false;
1576 const Record::Field *Field = R->findField(Offset);
1577 if (!Field)
1578 return false;
1579
1580 std::string TypeIdStr;
1581 llvm::raw_string_ostream SS(TypeIdStr);
1582 SS << "typeid(";
1585 SS << ").";
1586 SS << Field->Decl->getNameAsString();
1587
1588 S.FFDiag(S.Current->getSource(OpPC),
1589 diag::note_constexpr_access_unreadable_object)
1590 << AK_Read << TypeIdStr;
1591 return false;
1592}
1593
1594static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1595 uint32_t Off) {
1596 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1597 !CheckNull(S, OpPC, Ptr, CSK_Field))
1598 return false;
1599
1600 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1601 return false;
1602 if (!CheckArray(S, OpPC, Ptr))
1603 return false;
1604 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1605 return false;
1606
1607 if (Ptr.isIntegralPointer()) {
1608 if (std::optional<IntPointer> IntPtr =
1609 Ptr.asIntPointer().atOffset(S.Ctx, Off)) {
1610 S.Stk.push<Pointer>(std::move(*IntPtr));
1611 return true;
1612 }
1613 return false;
1614 }
1615
1616 if (!Ptr.isBlockPointer()) {
1617 // If we're trying to get the field of a TypeId pointer, try to produce a
1618 // proper diagnostic.
1619 if (Ptr.isTypeidPointer())
1620 return diagnoseTypeIdField(S, OpPC, Ptr, Off);
1621 return false;
1622 }
1623
1624 // We can't get the field of something that's not a record.
1625 if (!Ptr.getFieldDesc()->isRecord())
1626 return false;
1627
1628 if ((Ptr.getByteOffset() + Off) >= Ptr.block()->getSize())
1629 return false;
1630
1631 S.Stk.push<Pointer>(Ptr.atField(Off));
1632 return true;
1633}
1634
1635bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1636 const auto &Ptr = S.Stk.peek<Pointer>();
1637 return getField(S, OpPC, Ptr, Off);
1638}
1639
1640bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1641 const auto &Ptr = S.Stk.pop<Pointer>();
1642 return getField(S, OpPC, Ptr, Off);
1643}
1644
1645static bool getBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1646 uint32_t Off, bool NullOK) {
1647 if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Base))
1648 return false;
1649
1650 if (!Ptr.isBlockPointer()) {
1651 if (!Ptr.isIntegralPointer())
1652 return false;
1653 S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.Ctx, Off));
1654 return true;
1655 }
1656
1657 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1658 return false;
1659
1660 // In case this isn't something we can get the base of at all,
1661 // just return the pointer itself so it can be diagnosed later.
1662 if (!Ptr.getFieldDesc()->isRecord()) {
1663 S.Stk.push<Pointer>(Ptr);
1664 return true;
1665 }
1666
1667 const Pointer &Result = Ptr.atField(Off);
1668 if (Result.isPastEnd() || !Result.isBaseClass())
1669 return false;
1670 S.Stk.push<Pointer>(Result);
1671 return true;
1672}
1673
1674bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1675 const auto &Ptr = S.Stk.peek<Pointer>();
1676 return getBase(S, OpPC, Ptr.narrow(), Off, /*NullOK=*/true);
1677}
1678bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK) {
1679 const auto &Ptr = S.Stk.pop<Pointer>();
1680 return getBase(S, OpPC, Ptr.narrow(), Off, NullOK);
1681}
1682
1683bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK,
1684 const Type *TargetType) {
1685 const Pointer &Ptr = S.Stk.pop<Pointer>().narrow();
1686 if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))
1687 return false;
1688
1689 if (!Ptr.isBlockPointer()) {
1690 // FIXME: We don't have the necessary information in integral pointers.
1691 // The Descriptor only has a record, but that does of course not include
1692 // the potential derived classes of said record.
1693 S.Stk.push<Pointer>(Ptr);
1694 return true;
1695 }
1696
1697 if (!Ptr.getFieldDesc()->isRecord()) {
1698 S.Stk.push<Pointer>(Ptr);
1699 return true;
1700 }
1701
1702 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1703 return false;
1704 if (!CheckDowncast(S, OpPC, Ptr, Off))
1705 return false;
1706
1707 const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
1708 assert(TargetRecord);
1709
1710 if (TargetRecord->getDecl()->getCanonicalDecl() !=
1711 TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
1712 QualType MostDerivedType = Ptr.getDeclDesc()->getType();
1713 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
1714 << MostDerivedType << QualType(TargetType, 0);
1715 return false;
1716 }
1717
1718 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1719 return true;
1720}
1721
1722static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
1723 const Pointer &ThisPtr) {
1724 assert(Func->isConstructor());
1725
1726 if (Func->getParentDecl()->isInvalidDecl())
1727 return false;
1728
1729 const Descriptor *D = ThisPtr.getFieldDesc();
1730 // FIXME: I think this case is not 100% correct. E.g. a pointer into a
1731 // subobject of a composite array.
1732 if (!D->ElemRecord)
1733 return true;
1734
1735 if (S.getLangOpts().CPlusPlus26)
1736 return true;
1737
1738 if (D->ElemRecord->getNumVirtualBases() == 0)
1739 return true;
1740
1741 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base)
1742 << Func->getParentDecl();
1743 return false;
1744}
1745
1747 const Pointer &Ptr) {
1748 assert(Ptr.getLifetime() != Lifetime::Started);
1749 // Try to use the declaration for better diagnostics
1750 if (const Decl *D = Ptr.getDeclDesc()->asDecl()) {
1751 auto *ND = cast<NamedDecl>(D);
1752 S.FFDiag(ND->getLocation(), diag::note_constexpr_destroy_out_of_lifetime)
1753 << ND->getNameAsString();
1754 } else {
1755 S.FFDiag(Ptr.getDeclDesc()->getLocation(),
1756 diag::note_constexpr_destroy_out_of_lifetime)
1758 }
1759 return false;
1760}
1761
1762bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
1763 if (!CheckLive(S, OpPC, Ptr, AK_Destroy))
1764 return false;
1765 if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Destroy))
1766 return false;
1767 if (!CheckRange(S, OpPC, Ptr, AK_Destroy))
1768 return false;
1769
1770 if (Ptr.getLifetime() == Lifetime::Destroyed)
1771 return diagnoseOutOfLifetimeDestroy(S, OpPC, Ptr);
1772 if (Ptr.getLifetime() == Lifetime::Ended)
1773 return CheckLifetime(S, OpPC, Ptr, AK_Destroy);
1774
1775 // We _can_ call the destructor on the global variable we're checking constant
1776 // destruction for.
1777 if (S.checkingConstantDestruction(Ptr))
1778 return true;
1779
1780 // Can't call a dtor on a global variable.
1781 if (Ptr.block()->isStatic()) {
1782 const SourceInfo &E = S.Current->getSource(OpPC);
1783 S.FFDiag(E, diag::note_constexpr_modify_global);
1784 return false;
1785 }
1786 return CheckActive(S, OpPC, Ptr, AK_Destroy);
1787}
1788
1789/// Opcode. Check if the function decl can be called at compile time.
1792 return false;
1793
1794 const FunctionDecl *Definition = nullptr;
1795 bool HasBody = FD->hasBody(Definition);
1796
1797 if (Definition && HasBody &&
1798 (Definition->isConstexpr() || (S.Current->MSVCConstexprAllowed &&
1799 Definition->hasAttr<MSConstexprAttr>())))
1800 return true;
1801
1802 return diagnoseCallableDecl(S, OpPC, FD);
1803}
1804
1805bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType,
1806 bool SrcIsVoidPtr) {
1807 const auto &Ptr = S.Stk.peek<Pointer>();
1808 if (Ptr.isZero())
1809 return true;
1810 if (!Ptr.isBlockPointer())
1811 return true;
1812
1813 if (TargetType->isIntegerType())
1814 return true;
1815
1816 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
1817 bool HasValidResult = !Ptr.isZero();
1818
1819 if (HasValidResult) {
1820 if (S.getStdAllocatorCaller("allocate"))
1821 return true;
1822
1823 const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
1824 if (S.getLangOpts().CPlusPlus26 &&
1825 S.getASTContext().hasSimilarType(Ptr.getType(),
1826 QualType(TargetType, 0)))
1827 return true;
1828
1829 S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
1830 << E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus26
1831 << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
1832 } else if (!S.getLangOpts().CPlusPlus26) {
1833 const SourceInfo &E = S.Current->getSource(OpPC);
1834 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1835 << diag::ConstexprInvalidCastKind::CastFrom << "'void *'"
1836 << S.Current->getRange(OpPC);
1837 }
1838 }
1839
1840 QualType PtrType = Ptr.getType();
1841 if (PtrType->isRecordType() &&
1842 PtrType->getAsRecordDecl() != TargetType->getAsRecordDecl()) {
1843 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
1844 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
1845 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1846 }
1847 return true;
1848}
1849
1850static void compileFunction(InterpState &S, const Function *Func) {
1851 const FunctionDecl *Definition;
1852 if (!Func->getDecl()->hasBody(Definition))
1853 return;
1854 if (!Definition)
1855 return;
1856
1858 .compileFunc(Definition, const_cast<Function *>(Func));
1859}
1860
1862 uint32_t VarArgSize) {
1863 if (Func->hasThisPointer()) {
1864 size_t ArgSize = Func->getArgSize() + VarArgSize;
1865 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1866 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1867
1868 // If the current function is a lambda static invoker and
1869 // the function we're about to call is a lambda call operator,
1870 // skip the CheckInvoke, since the ThisPtr is a null pointer
1871 // anyway.
1872 if (!(S.Current->getFunction() &&
1874 Func->isLambdaCallOperator())) {
1875 if (!CheckInvoke(S, OpPC, ThisPtr, Func->isConstructor(),
1876 Func->isDestructor()))
1877 return false;
1878 }
1879
1881 return false;
1882 }
1883
1884 if (!Func->isFullyCompiled())
1886
1887 if (!CheckCallable(S, OpPC, Func))
1888 return false;
1889
1890 if (!CheckCallDepth(S, OpPC))
1891 return false;
1892
1893 auto *Memory = new char[InterpFrame::allocSize(Func)];
1894 auto *NewFrame = new (Memory) InterpFrame(S, Func, S.PC, VarArgSize);
1895 InterpFrame *FrameBefore = S.Current;
1896 S.Current = NewFrame;
1897
1898 InterpStateCCOverride CCOverride(S, Func->isImmediate());
1899 if (Interpret(S)) {
1900 assert(S.Current == FrameBefore);
1901 return true;
1902 }
1903
1904 InterpFrame::free(NewFrame);
1905 // Interpreting the function failed somehow. Reset to
1906 // previous state.
1907 S.Current = FrameBefore;
1908 return false;
1909}
1910bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
1911 uint32_t VarArgSize) {
1912
1913 // C doesn't have constexpr functions.
1914 if (!S.getLangOpts().CPlusPlus)
1915 return Invalid(S, OpPC);
1916
1917 assert(Func);
1918 auto cleanup = [&]() -> bool {
1920 return false;
1921 };
1922
1923 bool InstancePtrTracked = false;
1924 if (Func->hasThisPointer()) {
1925 size_t ArgSize = Func->getArgSize() + VarArgSize;
1926 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1927
1928 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1929
1930 // C++23 [expr.const]p5.6
1931 // an invocation of a virtual function ([class.virtual]) for an object whose
1932 // dynamic type is constexpr-unknown;
1933 if (ThisPtr.isDummy() && Func->isVirtual())
1934 return false;
1935
1936 // If the current function is a lambda static invoker and
1937 // the function we're about to call is a lambda call operator,
1938 // skip the CheckInvoke, since the ThisPtr is a null pointer
1939 // anyway.
1940 if (S.Current->getFunction() &&
1942 Func->isLambdaCallOperator()) {
1943 assert(ThisPtr.isZero());
1944 } else {
1945 if (!CheckInvoke(S, OpPC, ThisPtr, Func->isConstructor(),
1946 Func->isDestructor()))
1947 return cleanup();
1948
1949 if (Func->isCopyOrMoveOperator() || Func->isCopyOrMoveConstructor()) {
1950 const Pointer &RVOPtr =
1951 S.Stk.peek<Pointer>(ThisOffset - align(sizeof(Pointer)));
1952 if (!CheckInvoke(S, OpPC, RVOPtr, /*IsCtor=*/true, /*IsDtor=*/false))
1953 return cleanup();
1954 }
1955
1956 if (!Func->isConstructor() && !Func->isDestructor() &&
1957 !CheckActive(S, OpPC, ThisPtr, AK_MemberCall))
1958 return false;
1959 }
1960
1961 if (Func->isConstructor() && !checkConstructor(S, OpPC, Func, ThisPtr))
1962 return false;
1963 if (Func->isDestructor() && !checkDestructor(S, OpPC, ThisPtr))
1964 return false;
1965
1966 InstancePtrTracked = (Func->isConstructor() || Func->isDestructor());
1967 if (InstancePtrTracked)
1968 S.InitializingPtrs.push_back(ThisPtr.view());
1969 }
1970
1971 if (!Func->isFullyCompiled())
1973
1974 if (!CheckCallable(S, OpPC, Func))
1975 return cleanup();
1976
1977 // Do not evaluate any function calls in checkingPotentialConstantExpression
1978 // mode. Constructors will be aborted later when their initializers are
1979 // evaluated.
1980 if (S.checkingPotentialConstantExpression() && !Func->isConstructor())
1981 return false;
1982
1983 if (!CheckCallDepth(S, OpPC))
1984 return cleanup();
1985
1986 auto *Memory = new char[InterpFrame::allocSize(Func)];
1987 auto *NewFrame = new (Memory) InterpFrame(S, Func, S.PC, VarArgSize);
1988 InterpFrame *FrameBefore = S.Current;
1989 S.Current = NewFrame;
1990
1991 InterpStateCCOverride CCOverride(S, Func->isImmediate());
1992 bool Success = Interpret(S);
1993 // Remove initializing block again.
1994 if (InstancePtrTracked)
1995 S.InitializingPtrs.pop_back();
1996
1997 if (!Success) {
1998 InterpFrame::free(NewFrame);
1999 // Interpreting the function failed somehow. Reset to
2000 // previous state.
2001 S.Current = FrameBefore;
2002 return false;
2003 }
2004
2005 assert(S.Current == FrameBefore);
2006 return true;
2007}
2008
2009static bool getDynamicDecl(InterpState &S, CodePtr OpPC, PtrView TypePtr,
2010 const CXXRecordDecl *&DynamicDecl) {
2011
2012 if (S.InitializingPtrs.empty()) {
2013 TypePtr = TypePtr.stripBaseCasts();
2014 } else {
2015 auto depth = [](PtrView V) -> unsigned {
2016 unsigned C = 1;
2017 while (!V.isRoot()) {
2018 ++C;
2019 V = V.getBase();
2020 }
2021 return C;
2022 };
2023 // Consider a 'normal' diamond hierarchy:
2024 // A A 3
2025 // | |
2026 // B C 2
2027 // \ /
2028 // \ /
2029 // D 1
2030 // When we use a pointer of D*, cast it to B's A* and
2031 // use it during the construction of C*, the expected
2032 // dynamic type is B.
2033 PtrView InitPtr = S.InitializingPtrs.back();
2034 assert(depth(TypePtr) >= depth(InitPtr));
2035 unsigned D = depth(TypePtr) - depth(InitPtr);
2036 for (unsigned I = 0; I != D; ++I)
2037 TypePtr = TypePtr.getBase();
2038 }
2039
2040 QualType DynamicType = TypePtr.getType();
2041 if (TypePtr.Pointee->isStatic() || TypePtr.isConst()) {
2042 if (const VarDecl *VD = Pointer(TypePtr).getRootVarDecl();
2043 VD && !VD->isConstexpr()) {
2044 const Expr *E = S.Current->getExpr(OpPC);
2045 APValue V = Pointer(TypePtr).toAPValue(S.getASTContext());
2047 S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
2048 << AK_MemberCall << V.getAsString(S.getASTContext(), TT);
2049 return false;
2050 }
2051 }
2052
2053 if (DynamicType->isPointerType() || DynamicType->isReferenceType()) {
2054 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2055 } else if (DynamicType->isArrayType()) {
2056 const Type *ElemType = DynamicType->getPointeeOrArrayElementType();
2057 assert(ElemType);
2058 DynamicDecl = ElemType->getAsCXXRecordDecl();
2059 } else {
2060 DynamicDecl = DynamicType->getAsCXXRecordDecl();
2061 }
2062 return DynamicDecl != nullptr;
2063}
2064
2065namespace {
2066struct DynamicCastResult {
2067 UnsignedOrNone Offset = std::nullopt;
2068 bool Ambiguous = false;
2069
2070 bool valid() const { return !Ambiguous && Offset; }
2071
2072 void setOffset(unsigned O) {
2073 if (!Offset)
2074 Offset = O;
2075 else {
2076 Ambiguous = true;
2077 }
2078 }
2079
2080 void merge(DynamicCastResult C) {
2081 Ambiguous |= C.Ambiguous;
2082 if (C.Offset) {
2083 if (!Offset)
2084 Offset = C.Offset;
2085 else
2086 Ambiguous = true;
2087 }
2088 }
2089};
2090} // namespace
2091
2092// Walk UP the type hierarchy, starting at the decl of R to find Needle.
2093static DynamicCastResult findRecordBase(const ASTContext &Ctx, const Record *R,
2094 QualType Needle) {
2095 DynamicCastResult Res;
2096
2097 if (Ctx.hasSimilarType(Needle, Ctx.getCanonicalTagType(R->getDecl())))
2098 Res.setOffset(0);
2099
2100 for (const Record::Base &B : R->bases()) {
2101 auto N = findRecordBase(Ctx, B.R, Needle);
2102 if (N.Offset)
2103 N.Offset = *N.Offset + B.Offset;
2104 Res.merge(N);
2105 }
2106
2107 return Res;
2108}
2109
2110bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestTypePtr,
2111 bool IsReferenceCast) {
2112 const auto &Ptr = S.Stk.pop<Pointer>();
2113 QualType TargetType = QualType(DestTypePtr, 0);
2114
2115 if (Ptr.isConstexprUnknown()) {
2116 QualType T = Ptr.getType();
2117 const Expr *E = S.Current->getExpr(OpPC);
2118 APValue V = Ptr.toAPValue(S.getASTContext());
2120 S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
2121 << AK_DynamicCast << V.getAsString(S.getASTContext(), TT);
2122 return false;
2123 }
2124
2125 if (!Ptr.isBlockPointer() || !Ptr.getRecord())
2126 return false;
2127
2128 if (!Ptr.isInitialized())
2129 return diagnoseUninitialized(S, OpPC, Ptr, AK_Read);
2130
2131 // Our given pointer, limited by the base that's currently being initialized,
2132 // if any.
2133 PtrView LimitedPtr;
2134 if (S.InitializingPtrs.empty() ||
2135 S.InitializingPtrs.back().block() != Ptr.block()) {
2136 LimitedPtr = Ptr.stripBaseCasts().view();
2137 } else {
2138 LimitedPtr = S.InitializingPtrs.back();
2139 assert(LimitedPtr.block() == Ptr.block());
2140 }
2141 assert(LimitedPtr.getRecord());
2142
2143 // C++ [expr.dynamic.cast]p7:
2144 // If T is "pointer to cv void", then the result is a pointer to the most
2145 // derived object
2146 if (TargetType->isVoidType()) {
2147 S.Stk.push<Pointer>(LimitedPtr);
2148 return true;
2149 }
2150
2151 assert(!TargetType.isNull());
2152 assert(!TargetType->isVoidType());
2153 assert(TargetType->isRecordType());
2154
2155 // Helper lambdas.
2156 auto typesMatch = [&](QualType A, QualType B) -> bool {
2157 return S.getASTContext().hasSimilarType(A, B);
2158 };
2159 auto getRecord = [](PtrView P) -> const CXXRecordDecl * {
2160 assert(P.getRecord());
2161 return cast<CXXRecordDecl>(P.getRecord()->getDecl());
2162 };
2163
2164 auto baseIsPrivate = [&](PtrView P) -> bool {
2165 if (P.isRoot() || !P.isBaseClass())
2166 return false;
2167
2168 CXXBasePaths Paths;
2169 getRecord(P.getBase())->isDerivedFrom(getRecord(P), Paths);
2170
2171 // Through virtual bases, there might be more than one "direct" base. They
2172 // can have different access specifiers. They must all be private to be
2173 // considered private.
2174 return llvm::all_of(Paths, [](const CXXBasePath &P) -> bool {
2175 return P.Access == AS_private;
2176 });
2177 };
2178
2179 enum {
2180 DiagPrivateBase = 0,
2181 DiagNoBase = 1,
2182 DiagAmbiguous = 2,
2183 DiagPrivateSibling = 3
2184 };
2185
2186 auto diag = [&](int DiagKind, QualType ResultType) -> bool {
2187 // Pointer casts return nullptr on failure.
2188 if (!IsReferenceCast) {
2189 S.Stk.push<Pointer>(0, DestTypePtr);
2190 return true;
2191 }
2193 S.FFDiag(S.Current->getSource(OpPC),
2194 diag::note_constexpr_dynamic_cast_to_reference_failed)
2195 << DiagKind << ResultType << DynamicType << TargetType;
2196 return false;
2197 };
2198
2199 // Check if Ptr's dynamic type is derived from our target type at all.
2200 // If it isn't, diagnose this as "operand does not have base class of type
2201 // [...]".
2202 {
2203 CXXBasePaths Paths;
2204 getRecord(LimitedPtr)
2205 ->isDerivedFrom(TargetType->getAsCXXRecordDecl(), Paths);
2206 if (std::distance(Paths.begin(), Paths.end()) == 0 &&
2207 !typesMatch(LimitedPtr.getType(), TargetType)) {
2208 return diag(DiagNoBase, TargetType);
2209 }
2210 }
2211
2212 // Current base is already private.
2213 if (baseIsPrivate(Ptr.view()))
2214 return diag(DiagPrivateBase, Ptr.getType());
2215
2216 std::optional<PtrView> Result;
2217 // First, check simple downcasts without ambiguities.
2218 for (PtrView Iter = Ptr.view();;) {
2219 if (Iter.isRoot() || !Iter.isBaseClass())
2220 break;
2221
2222 if (typesMatch(TargetType, Iter.getType())) {
2223 Result = Iter;
2224 break;
2225 }
2226 // Moving DOWN the type hierarchy.
2227 Iter = Iter.getBase();
2228 }
2229
2230 // Simply walking down the type hierarchy has produced a valid result, use
2231 // that.
2232 if (Result) {
2233 if (baseIsPrivate(*Result))
2234 return diag(DiagPrivateBase, Result->getType());
2235 S.Stk.push<Pointer>(*Result);
2236 return true;
2237 }
2238
2239 // Otherwise, we need to do a deep hierarchy check.
2240 bool Ambiguous = false;
2241 for (PtrView Iter = LimitedPtr;;) {
2242 // If we can move up the hierarchy from this level and reach the target type
2243 // unambiguously, we're fine.
2244 auto R = findRecordBase(S.getASTContext(), Iter.getRecord(), TargetType);
2245
2246 if (R.valid()) {
2247 Result = Iter.atField(*R.Offset);
2248 break;
2249 } else if (R.Ambiguous) {
2250 Ambiguous = true;
2251 break;
2252 }
2253
2254 // This moves us DOWN the type hierarchy.
2255 Iter = Iter.getBase();
2256 if (Iter.isRoot() || !Iter.isBaseClass())
2257 break;
2258 }
2259
2260 if (Ambiguous)
2261 return diag(DiagAmbiguous, TargetType);
2262
2263 if (Result) {
2264 // Might still be invalid due to resulting in a private base though.
2265 if (baseIsPrivate(*Result))
2266 return diag(DiagPrivateSibling, TargetType);
2267 S.Stk.push<Pointer>(*Result);
2268 return true;
2269 }
2270
2271 // We couldn't find the requested base.
2272 return diag(DiagNoBase, TargetType);
2273}
2274
2276 uint32_t VarArgSize) {
2277 assert(Func->hasThisPointer());
2278 assert(Func->isVirtual());
2279 size_t ArgSize = Func->getArgSize() + VarArgSize;
2280 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2281 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2282
2283 if (!ThisPtr.isBlockPointer())
2284 return false;
2285
2286 const FunctionDecl *Callee = Func->getDecl();
2287
2288 const CXXRecordDecl *DynamicDecl = nullptr;
2289 if (!getDynamicDecl(S, OpPC, ThisPtr.view(), DynamicDecl))
2290 return false;
2291 assert(DynamicDecl);
2292
2293 const auto *StaticDecl = Func->getParentDecl();
2294 const auto *InitialFunction = cast<CXXMethodDecl>(Callee);
2295 const CXXMethodDecl *Overrider;
2296
2297 if (StaticDecl != DynamicDecl) {
2298 if (!DynamicDecl->isDerivedFrom(StaticDecl))
2299 return false;
2300 Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl,
2301 InitialFunction);
2302
2303 } else {
2304 Overrider = InitialFunction;
2305 }
2306
2307 // C++2a [class.abstract]p6:
2308 // the effect of making a virtual call to a pure virtual function [...] is
2309 // undefined
2310 if (Overrider->isPureVirtual()) {
2311 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,
2312 1)
2313 << Callee;
2314 S.Note(Callee->getLocation(), diag::note_declared_at);
2315 return false;
2316 }
2317
2318 if (Overrider != InitialFunction) {
2319 // DR1872: An instantiated virtual constexpr function can't be called in a
2320 // constant expression (prior to C++20). We can still constant-fold such a
2321 // call.
2322 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2323 const Expr *E = S.Current->getExpr(OpPC);
2324 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
2325 }
2326
2327 Func = S.getContext().getOrCreateFunction(Overrider);
2328
2329 const CXXRecordDecl *ThisFieldDecl =
2330 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2331 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2332 // If the function we call is further DOWN the hierarchy than the
2333 // FieldDesc of our pointer, just go up the hierarchy of this field
2334 // the furthest we can go.
2335 ThisPtr = ThisPtr.stripBaseCasts();
2336 }
2337 }
2338
2339 if (!Call(S, OpPC, Func, VarArgSize))
2340 return false;
2341
2342 // Covariant return types. The return type of Overrider is a pointer
2343 // or reference to a class type.
2344 if (Overrider != InitialFunction &&
2345 Overrider->getReturnType()->isPointerOrReferenceType() &&
2346 InitialFunction->getReturnType()->isPointerOrReferenceType()) {
2347 QualType OverriderPointeeType =
2348 Overrider->getReturnType()->getPointeeType();
2349 QualType InitialPointeeType =
2350 InitialFunction->getReturnType()->getPointeeType();
2351
2352 // Nothing to do if the types already match.
2353 if (S.getASTContext().hasSimilarType(InitialPointeeType,
2354 OverriderPointeeType))
2355 return true;
2356
2357 // We've called Overrider above, but calling code expects us to return what
2358 // InitialFunction returned. According to the rules for covariant return
2359 // types, what InitialFunction returns needs to be a base class of what
2360 // Overrider returns. So, we need to do an upcast here.
2361 unsigned Offset = S.getContext().collectBaseOffset(
2362 InitialPointeeType->getAsRecordDecl(),
2363 OverriderPointeeType->getAsRecordDecl());
2364 return GetPtrBasePop(S, OpPC, Offset, /*IsNullOK=*/true);
2365 }
2366
2367 return true;
2368}
2369
2370bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,
2371 uint32_t BuiltinID) {
2372 // A little arbitrary, but the current interpreter allows evaluation
2373 // of builtin functions in this mode, with some exceptions.
2374 if (BuiltinID == Builtin::BI__builtin_operator_new &&
2376 return false;
2377
2378 return InterpretBuiltin(S, OpPC, CE, BuiltinID);
2379}
2380
2381bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2382 const CallExpr *CE) {
2383 const Pointer &Ptr = S.Stk.pop<Pointer>();
2384
2385 if (Ptr.isZero()) {
2386 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_null_callee)
2387 << const_cast<Expr *>(CE->getCallee()) << CE->getSourceRange();
2388 return false;
2389 }
2390
2391 if (!Ptr.isFunctionPointer())
2392 return Invalid(S, OpPC);
2393
2394 const Function *F = Ptr.asFunctionPointer().Func;
2395 assert(F);
2396 // Don't allow calling block pointers.
2397 if (!F->getDecl())
2398 return Invalid(S, OpPC);
2399
2400 // This happens when the call expression has been cast to
2401 // something else, but we don't support that.
2402 if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
2404 return false;
2405
2406 // Check argument nullability state.
2407 if (F->hasNonNullAttr()) {
2408 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2409 return false;
2410 }
2411
2412 // Can happen when casting function pointers around.
2413 QualType CalleeType = CE->getCallee()->getType();
2414 if (CalleeType->isPointerType() &&
2416 F->getDecl()->getType(), CalleeType->getPointeeType())) {
2417 return false;
2418 }
2419
2420 // We nedd to compile (and check) early for function pointer calls
2421 // because the Call/CallVirt below might access the instance pointer
2422 // but the Function's information about them is wrong.
2423 if (!F->isFullyCompiled())
2424 compileFunction(S, F);
2425
2426 if (!CheckCallable(S, OpPC, F))
2427 return false;
2428
2429 assert(ArgSize >= F->getWrittenArgSize());
2430 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2431
2432 // We need to do this explicitly here since we don't have the necessary
2433 // information to do it automatically.
2434 if (F->hasExplicitThisPointer())
2435 VarArgSize -= align(primSize(PT_Ptr));
2436
2437 if (F->isVirtual())
2438 return CallVirt(S, OpPC, F, VarArgSize);
2439
2440 return Call(S, OpPC, F, VarArgSize);
2441}
2442
2444 if (const Record *R = Ptr.getRecord()) {
2445 Ptr.startLifetime();
2446
2447 for (const Record::Field &Fi : R->fields()) {
2448 PtrView FP = Ptr.atField(Fi.Offset);
2449 if (FP.getLifetime() != Lifetime::Started)
2451 }
2452 return;
2453 }
2454
2455 if (const Descriptor *FieldDesc = Ptr.getFieldDesc();
2456 FieldDesc->isCompositeArray()) {
2457 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
2458 PtrView EP = Ptr.atIndex(I).narrow();
2459 if (EP.getLifetime() != Lifetime::Started)
2461 }
2462 return;
2463 }
2464
2465 Ptr.startLifetime();
2466}
2467
2470 return true;
2471
2472 const auto &Ptr = S.Current->getThis();
2473 if (!Ptr.isBlockPointer())
2474 return false;
2475 startLifetimeRecurse(Ptr.view());
2476 return true;
2477}
2478
2481 return true;
2482
2483 const auto &Ptr = S.Current->getThis();
2484 if (!Ptr.isBlockPointer())
2485 return false;
2486 Ptr.startLifetime();
2487 return true;
2488}
2489
2490// FIXME: It might be better to the recursing as part of the generated code for
2491// a destructor?
2493 if (const Record *R = Ptr.getRecord()) {
2494 Ptr.setLifeState(L);
2495 for (const Record::Field &Fi : R->fields())
2496 setLifeStateRecurse(Ptr.atField(Fi.Offset), L);
2497 return;
2498 }
2499
2500 if (const Descriptor *FieldDesc = Ptr.getFieldDesc();
2501 FieldDesc->isCompositeArray()) {
2502 // No endLifetime() for primitive array roots.
2503 if (Ptr.getFieldDesc()->isPrimitiveArray())
2504 assert(Ptr.getLifetime() == Lifetime::Started);
2505 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
2506 setLifeStateRecurse(Ptr.atIndex(I).narrow(), L);
2507 return;
2508 }
2509
2510 Ptr.setLifeState(L);
2511}
2512
2513/// Ends the lifetime of the peek'd pointer.
2515 const auto &Ptr = S.Stk.peek<Pointer>();
2516 if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
2517 return false;
2518
2519 setLifeStateRecurse(Ptr.view().narrow(), Lifetime::Ended);
2520 return true;
2521}
2522
2523/// Ends the lifetime of the pop'd pointer.
2525 const auto &Ptr = S.Stk.pop<Pointer>();
2526 if (!checkDestructor(S, OpPC, Ptr))
2527 return false;
2528 setLifeStateRecurse(Ptr.view().narrow(), Lifetime::Ended);
2529 return true;
2530}
2531
2533 const auto &Ptr = S.Stk.peek<Pointer>();
2534 if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
2535 return false;
2536
2537 setLifeStateRecurse(Ptr.view().narrow(), Lifetime::Destroyed);
2538 return true;
2539}
2540
2542 std::optional<uint64_t> ArraySize) {
2543 Pointer &Orig = S.Stk.peek<Pointer>();
2544 Pointer Ptr = Orig;
2545
2546 auto directBaseIsUnion = [](const Pointer &Ptr) -> bool {
2547 if (Ptr.isArrayElement())
2548 return false;
2549 const Record *R = Ptr.getBase().getRecord();
2550 return R && R->isUnion();
2551 };
2552
2553 if (Ptr.inUnion() && directBaseIsUnion(Ptr))
2554 Ptr.activate();
2555
2556 if (Ptr.isZero()) {
2557 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_null)
2558 << AK_Construct;
2559 return false;
2560 }
2561
2562 if (!Ptr.isBlockPointer())
2563 return false;
2564
2565 if (!CheckRange(S, OpPC, Ptr, AK_Construct))
2566 return false;
2567
2568 startLifetimeRecurse(Ptr.view());
2569
2570 // Similar to CheckStore(), but with the additional CheckTemporary() call and
2571 // the AccessKinds are different.
2572 if (!Ptr.block()->isAccessible()) {
2573 if (!CheckExtern(S, OpPC, Ptr))
2574 return false;
2575 if (!CheckLive(S, OpPC, Ptr, AK_Construct))
2576 return false;
2577 return CheckDummy(S, OpPC, Ptr.block(), AK_Construct);
2578 }
2579 if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct))
2580 return false;
2581
2582 // CheckLifetime for this and all base pointers.
2583 for (PtrView P = Ptr.view();;) {
2584 if (!CheckLifetime(S, OpPC, P.getLifetime(), P.Pointee, AK_Construct))
2585 return false;
2586
2587 if (P.isRoot())
2588 break;
2589 P = P.getBase();
2590 }
2591
2592 if (!CheckRange(S, OpPC, Ptr, AK_Construct))
2593 return false;
2594 if (!CheckGlobal(S, OpPC, Ptr))
2595 return false;
2596 if (!CheckConst(S, OpPC, Ptr))
2597 return false;
2598 if (!S.inConstantContext() && isConstexprUnknown(Ptr))
2599 return false;
2600
2601 if (!InvalidNewDeleteExpr(S, OpPC, E))
2602 return false;
2603
2604 const auto *NewExpr = cast<CXXNewExpr>(E);
2605 const ASTContext &ASTCtx = S.getASTContext();
2606 QualType StorageType = Ptr.getType();
2607 QualType AllocType;
2608 if (ArraySize) {
2609 AllocType = ASTCtx.getConstantArrayType(
2610 NewExpr->getAllocatedType(),
2611 APInt(64, static_cast<uint64_t>(*ArraySize), false), nullptr,
2613 } else {
2614 AllocType = NewExpr->getAllocatedType();
2615 }
2616
2617 if (AllocType->isArrayType() && Ptr.isArrayElement() &&
2618 Ptr.expand().getIndex() == 0) {
2619 // The destination of placement new is pointing to the first element
2620 // of an array. There's a special case in [expr.const]: "[...] if T is an
2621 // array type, to the first element of such an object [...]". Handle
2622 // that case here by using the base of the Pointer.
2623 QualType AllocElementType =
2624 ASTCtx.getAsArrayType(AllocType)->getElementType();
2625 if (ASTCtx.hasSimilarType(AllocElementType, StorageType)) {
2626 StorageType = Ptr.expand().getArray().getType();
2627 Orig = Orig.expand();
2628 }
2629 }
2630
2631 if (!ASTCtx.hasSimilarType(AllocType, StorageType)) {
2632 S.FFDiag(S.Current->getLocation(OpPC),
2633 diag::note_constexpr_placement_new_wrong_type)
2634 << StorageType << AllocType;
2635 return false;
2636 }
2637
2638 // Can't activate fields in a union, unless the direct base is the union.
2639 if (Ptr.inUnion() && !Ptr.isActive() && !directBaseIsUnion(Ptr))
2640 return CheckActive(S, OpPC, Ptr, AK_Construct);
2641
2642 return true;
2643}
2644
2646 assert(E);
2647
2648 if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
2649 const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
2650
2651 if (NewExpr->getNumPlacementArgs() > 0) {
2652 // This is allowed pre-C++26, but only an std function or if
2653 // [[msvc::constexpr]] was used.
2654 if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction() ||
2656 return true;
2657
2658 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
2659 << /*C++26 feature*/ 1 << E->getSourceRange();
2660 } else if (
2661 !OperatorNew
2662 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
2663 S.FFDiag(S.Current->getSource(OpPC),
2664 diag::note_constexpr_new_non_replaceable)
2665 << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
2666 return false;
2667 } else if (!S.getLangOpts().CPlusPlus26 &&
2668 NewExpr->getNumPlacementArgs() == 1 &&
2669 !OperatorNew->isReservedGlobalPlacementOperator()) {
2670 if (!S.getLangOpts().CPlusPlus26) {
2671 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
2672 << /*Unsupported*/ 0 << E->getSourceRange();
2673 return false;
2674 }
2675 return true;
2676 }
2677 } else {
2678 const auto *DeleteExpr = cast<CXXDeleteExpr>(E);
2679 const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
2680 if (!OperatorDelete
2681 ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
2682 S.FFDiag(S.Current->getSource(OpPC),
2683 diag::note_constexpr_new_non_replaceable)
2684 << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
2685 return false;
2686 }
2687 }
2688
2689 return false;
2690}
2691
2693 const FixedPoint &FP) {
2694 const Expr *E = S.Current->getExpr(OpPC);
2697 E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
2698 << FP.toDiagnosticString(S.getASTContext()) << E->getType();
2699 }
2700 S.CCEDiag(E, diag::note_constexpr_overflow)
2701 << FP.toDiagnosticString(S.getASTContext()) << E->getType();
2702 return S.noteUndefinedBehavior();
2703}
2704
2705bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index) {
2706 const SourceInfo &Loc = S.Current->getSource(OpPC);
2707 S.FFDiag(Loc,
2708 diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)
2709 << Index;
2710 return false;
2711}
2712
2714 const Pointer &Ptr, unsigned BitWidth) {
2715 SourceInfo E = S.Current->getSource(OpPC);
2716 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2717 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2718
2719 if (Ptr.isIntegralPointer())
2720 return true;
2721
2722 if (Ptr.isDummy()) {
2723 if (!CheckIntegralAddressCast(S, OpPC, BitWidth))
2724 return false;
2725 return Ptr.getIndex() == 0;
2726 }
2727
2728 if (!Ptr.isZero()) {
2729 // Only allow based lvalue casts if they are lossless.
2730 if (!CheckIntegralAddressCast(S, OpPC, BitWidth))
2731 return Invalid(S, OpPC);
2732 }
2733 return true;
2734}
2735
2736bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth) {
2738 BitWidth);
2739}
2740
2741bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2742 const Pointer &Ptr = S.Stk.pop<Pointer>();
2743
2744 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))
2745 return false;
2746
2747 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
2748 Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));
2749
2751 return true;
2752}
2753
2754bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2755 const Pointer &Ptr = S.Stk.pop<Pointer>();
2756
2757 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))
2758 return false;
2759
2760 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
2761 Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));
2762
2764 return true;
2765}
2766
2767bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
2768 bool TargetIsUCharOrByte) {
2769 // This is always fine.
2770 if (!HasIndeterminateBits)
2771 return true;
2772
2773 // Indeterminate bits can only be bitcast to unsigned char or std::byte.
2774 if (TargetIsUCharOrByte)
2775 return true;
2776
2777 const Expr *E = S.Current->getExpr(OpPC);
2778 QualType ExprType = E->getType();
2779 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
2780 << ExprType << S.getLangOpts().CharIsSigned << E->getSourceRange();
2781 return false;
2782}
2783
2785 if (isConstexprUnknown(B)) {
2786 S.Stk.push<Pointer>(B);
2787 return true;
2788 }
2789
2790 const auto &ID = B->getBlockDesc<const InlineDescriptor>();
2791 if (!ID.IsInitialized) {
2793 S.FFDiag(S.Current->getSource(OpPC),
2794 diag::note_constexpr_use_uninit_reference);
2795 return false;
2796 }
2797
2798 assert(B->getDescriptor()->getPrimType() == PT_Ptr);
2799 S.Stk.push<Pointer>(B->deref<Pointer>());
2800 return true;
2801}
2802
2803bool GetTypeid(InterpState &S, const Type *TypePtr, const Type *TypeInfoType) {
2804 S.Stk.push<Pointer>(TypePtr, TypeInfoType);
2805 return true;
2806}
2807
2808bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
2809 const auto &P = S.Stk.pop<Pointer>();
2810
2811 if (!P.isBlockPointer())
2812 return false;
2813
2814 if (P.isConstexprUnknown()) {
2815 QualType DynamicType = P.getType();
2816 const Expr *E = S.Current->getExpr(OpPC);
2817 APValue V = P.toAPValue(S.getASTContext());
2819 S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
2820 << AK_TypeId << V.getAsString(S.getASTContext(), TT);
2821 return false;
2822 }
2823
2824 // Pick the most-derived type.
2825 CanQualType T = P.stripBaseCasts().getType()->getCanonicalTypeUnqualified();
2826 // ... unless we're currently constructing this object.
2827 // FIXME: We have a similar check to this in more places.
2828 if (S.Current->getFunction()) {
2829 for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
2830 if (const Function *Func = Frame->getFunction();
2831 Func && (Func->isConstructor() || Func->isDestructor()) &&
2832 P.block() == Frame->getThis().block()) {
2834 Func->getParentDecl());
2835 break;
2836 }
2837 }
2838 }
2839
2840 S.Stk.push<Pointer>(T->getTypePtr(), TypeInfoType);
2841 return true;
2842}
2843
2845 const auto *E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC));
2846 S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
2847 << E->getExprOperand()->getType()
2848 << E->getExprOperand()->getSourceRange();
2849 return false;
2850}
2851
2853 const Pointer &RHS) {
2854 if (!LHS.pointsToStringLiteral() || !RHS.pointsToStringLiteral())
2855 return false;
2856
2857 unsigned LHSOffset = LHS.isOnePastEnd() ? LHS.getNumElems() : LHS.getIndex();
2858 unsigned RHSOffset = RHS.isOnePastEnd() ? RHS.getNumElems() : RHS.getIndex();
2859 const auto *LHSLit = cast<StringLiteral>(LHS.getDeclDesc()->asExpr());
2860 const auto *RHSLit = cast<StringLiteral>(RHS.getDeclDesc()->asExpr());
2861
2862 StringRef LHSStr(LHSLit->getBytes());
2863 unsigned LHSLength = LHSStr.size();
2864 StringRef RHSStr(RHSLit->getBytes());
2865 unsigned RHSLength = RHSStr.size();
2866
2867 int32_t IndexDiff = RHSOffset - LHSOffset;
2868 if (IndexDiff < 0) {
2869 if (static_cast<int32_t>(LHSLength) < -IndexDiff)
2870 return false;
2871 LHSStr = LHSStr.drop_front(-IndexDiff);
2872 } else {
2873 if (static_cast<int32_t>(RHSLength) < IndexDiff)
2874 return false;
2875 RHSStr = RHSStr.drop_front(IndexDiff);
2876 }
2877
2878 unsigned ShorterCharWidth;
2879 StringRef Shorter;
2880 StringRef Longer;
2881 if (LHSLength < RHSLength) {
2882 ShorterCharWidth = LHS.getFieldDesc()->getElemDataSize();
2883 Shorter = LHSStr;
2884 Longer = RHSStr;
2885 } else {
2886 ShorterCharWidth = RHS.getFieldDesc()->getElemDataSize();
2887 Shorter = RHSStr;
2888 Longer = LHSStr;
2889 }
2890
2891 // The null terminator isn't included in the string data, so check for it
2892 // manually. If the longer string doesn't have a null terminator where the
2893 // shorter string ends, they aren't potentially overlapping.
2894 for (unsigned NullByte : llvm::seq(ShorterCharWidth)) {
2895 if (Shorter.size() + NullByte >= Longer.size())
2896 break;
2897 if (Longer[Shorter.size() + NullByte])
2898 return false;
2899 }
2900 return Shorter == Longer.take_front(Shorter.size());
2901}
2902
2904 if (T == PT_IntAPS) {
2905 auto &Val = Ptr.deref<IntegralAP<true>>();
2906 if (!Val.singleWord()) {
2907 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
2908 Val.take(NewMemory);
2909 }
2910 } else if (T == PT_IntAP) {
2911 auto &Val = Ptr.deref<IntegralAP<false>>();
2912 if (!Val.singleWord()) {
2913 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
2914 Val.take(NewMemory);
2915 }
2916 } else if (T == PT_Float) {
2917 auto &Val = Ptr.deref<Floating>();
2918 if (!Val.singleWord()) {
2919 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
2920 Val.take(NewMemory);
2921 }
2922 } else if (T == PT_MemberPtr) {
2923 auto &Val = Ptr.deref<MemberPointer>();
2924 unsigned PathLength = Val.getPathLength();
2925 auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
2926 std::copy_n(Val.path(), PathLength, NewPath);
2927 Val.takePath(NewPath);
2928 }
2929}
2930
2931template <typename T>
2933 assert(needsAlloc<T>());
2934 if constexpr (std::is_same_v<T, MemberPointer>) {
2935 auto &Val = Ptr.deref<MemberPointer>();
2936 unsigned PathLength = Val.getPathLength();
2937 auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
2938 std::copy_n(Val.path(), PathLength, NewPath);
2939 Val.takePath(NewPath);
2940 } else {
2941 auto &Val = Ptr.deref<T>();
2942 if (!Val.singleWord()) {
2943 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
2944 Val.take(NewMemory);
2945 }
2946 }
2947}
2948
2950 if (const Record *R = Ptr.getRecord()) {
2951 for (const Record::Field &Fi : R->fields()) {
2952 if (Fi.Desc->isPrimitive()) {
2953 TYPE_SWITCH_ALLOC(Fi.Desc->getPrimType(), {
2954 copyPrimitiveMemory<T>(S, Ptr.atField(Fi.Offset));
2955 });
2956 } else {
2957 finishGlobalRecurse(S, Ptr.atField(Fi.Offset));
2958 }
2959 }
2960 return;
2961 }
2962
2963 if (const Descriptor *D = Ptr.getFieldDesc(); D && D->isArray()) {
2964 unsigned NumElems = D->getNumElems();
2965 if (NumElems == 0)
2966 return;
2967
2968 if (D->isPrimitiveArray()) {
2969 PrimType PT = D->getPrimType();
2970 if (!needsAlloc(PT))
2971 return;
2972 assert(NumElems >= 1);
2973 PtrView EP = Ptr.atIndex(0);
2974 bool AllSingleWord = true;
2975 TYPE_SWITCH_ALLOC(PT, {
2976 if (!EP.deref<T>().singleWord()) {
2978 AllSingleWord = false;
2979 }
2980 });
2981 if (AllSingleWord)
2982 return;
2983 for (unsigned I = 1; I != D->getNumElems(); ++I) {
2984 PtrView EP = Ptr.atIndex(I);
2985 copyPrimitiveMemory(S, EP, PT);
2986 }
2987 } else {
2988 assert(D->isCompositeArray());
2989 for (unsigned I = 0; I != D->getNumElems(); ++I) {
2990 PtrView EP = Ptr.atIndex(I).narrow();
2991 finishGlobalRecurse(S, EP);
2992 }
2993 }
2994 }
2995}
2996
2998 const Pointer &Ptr = S.Stk.pop<Pointer>();
2999
3000 finishGlobalRecurse(S, Ptr.view());
3001 if (Ptr.canBeInitialized()) {
3002 Ptr.initialize();
3003 Ptr.activate();
3004 }
3005
3006 return true;
3007}
3008
3009bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal) {
3010 const SourceLocation &Loc = S.Current->getLocation(OpPC);
3011
3012 switch (Kind) {
3014 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
3015 << diag::ConstexprInvalidCastKind::Reinterpret
3016 << S.Current->getRange(OpPC);
3017 return !Fatal;
3019 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
3020 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3021 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
3022 return !Fatal;
3023 case CastKind::Volatile:
3025 const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
3026 if (S.getLangOpts().CPlusPlus)
3027 S.FFDiag(E, diag::note_constexpr_access_volatile_type)
3028 << AK_Read << E->getSubExpr()->getType();
3029 else
3030 S.FFDiag(E);
3031 }
3032
3033 return false;
3034 case CastKind::Dynamic:
3035 assert(!S.getLangOpts().CPlusPlus20);
3036 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
3037 << diag::ConstexprInvalidCastKind::Dynamic;
3038 return true;
3039 }
3040 llvm_unreachable("Unhandled CastKind");
3041 return false;
3042}
3043
3044bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
3045 assert(S.Current->getFunction());
3046 // FIXME: We iterate the scope once here and then again in the destroy() call
3047 // below.
3048 for (auto &Local : S.Current->getFunction()->getScope(I).locals_reverse()) {
3049 if (!S.Current->getLocalBlock(Local.Offset)->isInitialized())
3050 continue;
3051 const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset);
3052 if (Ptr.getLifetime() == Lifetime::Ended)
3053 return diagnoseOutOfLifetimeDestroy(S, OpPC, Ptr);
3054 }
3055
3056 S.Current->destroy(I);
3057 return true;
3058}
3059
3060// Perform a cast towards the class of the Decl (either up or down the
3061// hierarchy).
3063 const MemberPointer &MemberPtr,
3064 int32_t BaseOffset,
3065 const RecordDecl *BaseDecl) {
3066 const CXXRecordDecl *Expected;
3067 if (MemberPtr.getPathLength() >= 2)
3068 Expected = MemberPtr.getPathEntry(MemberPtr.getPathLength() - 2);
3069 else
3070 Expected = MemberPtr.getRecordDecl();
3071
3072 assert(Expected);
3073 if (Expected->getCanonicalDecl() != BaseDecl->getCanonicalDecl()) {
3074 // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
3075 // if B does not contain the original member and is not a base or
3076 // derived class of the class containing the original member, the result
3077 // of the cast is undefined.
3078 // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
3079 // (D::*). We consider that to be a language defect.
3080 return false;
3081 }
3082
3083 unsigned OldPathLength = MemberPtr.getPathLength();
3084 unsigned NewPathLength = OldPathLength - 1;
3085 bool IsDerivedMember = NewPathLength != 0;
3086 auto *NewPath = S.allocMemberPointerPath(NewPathLength);
3087 std::copy_n(MemberPtr.path(), NewPathLength, NewPath);
3088
3089 S.Stk.push<MemberPointer>(MemberPtr.atInstanceBase(BaseOffset, NewPathLength,
3090 NewPath, IsDerivedMember));
3091 return true;
3092}
3093
3095 const MemberPointer &MemberPtr,
3096 int32_t BaseOffset,
3097 const RecordDecl *BaseDecl,
3098 bool IsDerivedMember) {
3099 unsigned OldPathLength = MemberPtr.getPathLength();
3100 unsigned NewPathLength = OldPathLength + 1;
3101
3102 auto *NewPath = S.allocMemberPointerPath(NewPathLength);
3103 std::copy_n(MemberPtr.path(), OldPathLength, NewPath);
3104 NewPath[OldPathLength] = cast<CXXRecordDecl>(BaseDecl);
3105
3106 S.Stk.push<MemberPointer>(MemberPtr.atInstanceBase(BaseOffset, NewPathLength,
3107 NewPath, IsDerivedMember));
3108 return true;
3109}
3110
3111/// DerivedToBaseMemberPointer
3113 const RecordDecl *BaseDecl) {
3114 const auto &Ptr = S.Stk.pop<MemberPointer>();
3115
3116 if (!Ptr.isDerivedMember() && Ptr.hasPath())
3117 return castBackMemberPointer(S, Ptr, Off, BaseDecl);
3118
3119 bool IsDerivedMember = Ptr.isDerivedMember() || !Ptr.hasPath();
3120 return appendToMemberPointer(S, Ptr, Off, BaseDecl, IsDerivedMember);
3121}
3122
3123/// BaseToDerivedMemberPointer
3125 const RecordDecl *BaseDecl) {
3126 const auto &Ptr = S.Stk.pop<MemberPointer>();
3127
3128 if (!Ptr.isDerivedMember()) {
3129 // Simply append.
3130 return appendToMemberPointer(S, Ptr, Off, BaseDecl,
3131 /*IsDerivedMember=*/false);
3132 }
3133
3134 return castBackMemberPointer(S, Ptr, Off, BaseDecl);
3135}
3136
3138 S.Stk.push<MemberPointer>(D);
3139 return true;
3140}
3141
3143 const auto &MP = S.Stk.pop<MemberPointer>();
3144
3145 if (!MP.isBaseCastPossible())
3146 return false;
3147
3148 S.Stk.push<Pointer>(MP.getBase());
3149 return true;
3150}
3151
3153 const auto &MP = S.Stk.pop<MemberPointer>();
3154
3155 const ValueDecl *D = MP.getDecl();
3156 const auto *FD = dyn_cast_if_present<FunctionDecl>(D);
3157 if (!FD)
3158 return false;
3159
3160 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
3161 if (!Method)
3162 return false;
3163
3164 const Pointer &Base = MP.getBase();
3165 // The method must be accessible via the base of the MemberPointer.
3166 const CXXRecordDecl *MethodParent = Method->getParent();
3167 if (!Base.getRecord() || Base.getRecord()->getDecl() != MethodParent)
3168 return false;
3169
3170 const auto *Func = S.getContext().getOrCreateFunction(FD);
3171 if (!Func)
3172 return false;
3173 S.Stk.push<Pointer>(Func);
3174 return true;
3175}
3176
3177/// Just append the given Entry to the MemberPointer's path.
3178/// This is used to re-inject APValues into the bytecode interpreter.
3180 bool IsDerived) {
3181 const auto &MemberPtr = S.Stk.pop<MemberPointer>();
3182
3183 unsigned OldPathLength = MemberPtr.getPathLength();
3184 unsigned NewPathLength = OldPathLength + 1;
3185
3186 auto *NewPath = S.allocMemberPointerPath(NewPathLength);
3187 std::copy_n(MemberPtr.path(), OldPathLength, NewPath);
3188 NewPath[OldPathLength] = cast<CXXRecordDecl>(Entry);
3189
3191 MemberPtr.withPath(NewPathLength, NewPath, IsDerived));
3192 return true;
3193}
3194
3195template <bool Signed>
3196static bool floatAPCast(InterpState &S, CodePtr OpPC, const Floating &F,
3197 uint32_t BitWidth, uint32_t FPOI) {
3198 APSInt Result(BitWidth, /*IsUnsigned=*/!Signed);
3199 auto Status = F.convertToInteger(Result);
3200
3201 // Float-to-Integral overflow check.
3202 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite() &&
3203 !handleOverflow(S, OpPC, F.getAPFloat()))
3204 return false;
3205
3207
3208 auto ResultAP = S.allocAP<IntegralAP<Signed>>(BitWidth);
3209 ResultAP.copy(Result);
3210
3211 S.Stk.push<IntegralAP<Signed>>(ResultAP);
3212
3213 return CheckFloatResult(S, OpPC, F, Status, FPO);
3214}
3215
3216bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth,
3217 uint32_t FPOI) {
3218 Floating F = S.Stk.pop<Floating>();
3219 return floatAPCast<false>(S, OpPC, F, BitWidth, FPOI);
3220}
3221
3222bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth,
3223 uint32_t FPOI) {
3224 Floating F = S.Stk.pop<Floating>();
3225 return floatAPCast<true>(S, OpPC, F, BitWidth, FPOI);
3226}
3227
3228// FIXME: Would be nice to generate this instead of hardcoding it here.
3229[[maybe_unused]] static constexpr bool OpReturns(Opcode Op) {
3230 return Op == OP_RetVoid || Op == OP_RetValue || Op == OP_NoRet ||
3231 Op == OP_RetSint8 || Op == OP_RetUint8 || Op == OP_RetSint16 ||
3232 Op == OP_RetUint16 || Op == OP_RetSint32 || Op == OP_RetUint32 ||
3233 Op == OP_RetSint64 || Op == OP_RetUint64 || Op == OP_RetIntAP ||
3234 Op == OP_RetIntAPS || Op == OP_RetBool || Op == OP_RetFixedPoint ||
3235 Op == OP_RetPtr || Op == OP_RetMemberPtr || Op == OP_RetFloat ||
3236 Op == OP_EndSpeculation;
3237}
3238
3239#if USE_TAILCALLS
3240PRESERVE_NONE static bool InterpNext(InterpState &S);
3241#endif
3242
3243// The dispatcher functions read the opcode arguments from the
3244// bytecode and call the implementation function.
3245#define GET_INTERPFN_DISPATCHERS
3246#include "Opcodes.inc"
3247#undef GET_INTERPFN_DISPATCHERS
3248
3250// Array of the dispatcher functions defined above.
3252#define GET_INTERPFN_LIST
3253#include "Opcodes.inc"
3254#undef GET_INTERPFN_LIST
3255};
3256
3257#if USE_TAILCALLS
3258// Read the next opcode and call the dispatcher function.
3259PRESERVE_NONE static bool InterpNext(InterpState &S) {
3260 auto Op = S.PC.read<Opcode>();
3261 auto Fn = InterpFunctions[Op];
3262 MUSTTAIL return Fn(S);
3263}
3264#endif
3265
3267 // The current stack frame when we started Interpret().
3268 // This is being used by the ops to determine wheter
3269 // to return from this function and thus terminate
3270 // interpretation.
3271 assert(!S.Current->isRoot());
3272
3273 S.PC = S.Current->getFunction()->getCodeBegin();
3274
3275#if USE_TAILCALLS
3276 return InterpNext(S);
3277#else
3278 while (true) {
3279 auto Op = S.PC.read<Opcode>();
3280 auto Fn = InterpFunctions[Op];
3281
3282 if (!Fn(S))
3283 return false;
3284 if (OpReturns(Op))
3285 break;
3286 }
3287 return true;
3288#endif
3289}
3290
3291/// This is used to implement speculative execution via __builtin_constant_p
3292/// when we generate bytecode.
3293///
3294/// The setup here is that we use the same tailcall mechanism for speculative
3295/// evaluation that we use for the regular one.
3296/// Since each speculative execution ends with an EndSpeculation opcode,
3297/// that one does NOT call InterpNext() but simply returns true.
3298/// This way, we return back to this function when we see an EndSpeculation,
3299/// OR (of course), when we encounter an error and one of the opcodes
3300/// returns false.
3301PRESERVE_NONE static bool BCP(InterpState &S, CodePtr OpPC, int32_t Offset,
3302 PrimType PT) {
3303 // PC after reading the BCP opcode and both Offset/PT arguments.
3304 [[maybe_unused]] CodePtr PCBefore = S.PC;
3305 size_t StackSizeBefore = S.Stk.size();
3306
3307 // Speculation depth must be at least 1 here, since we must have
3308 // passed a StartSpeculation op before.
3309#ifndef NDEBUG
3310 [[maybe_unused]] unsigned DepthBefore = S.SpeculationDepth;
3311 assert(DepthBefore >= 1);
3312#endif
3313
3314 auto SpeculativeInterp = [&S]() -> bool {
3315 // Ignore diagnostics during speculative execution.
3316 PushIgnoreDiags(S);
3317 auto _ = llvm::scope_exit([&]() { PopIgnoreDiags(S); });
3318
3319#if USE_TAILCALLS
3320 auto Op = S.PC.read<Opcode>();
3321 auto Fn = InterpFunctions[Op];
3322 return Fn(S);
3323#else
3324 while (true) {
3325 auto Op = S.PC.read<Opcode>();
3326 auto Fn = InterpFunctions[Op];
3327
3328 if (!Fn(S))
3329 return false;
3330 if (OpReturns(Op))
3331 break;
3332 }
3333 return true;
3334#endif
3335 };
3336
3337 if (SpeculativeInterp()) {
3338 // Speculation must've ended naturally via a EndSpeculation opcode.
3339 assert(S.SpeculationDepth == DepthBefore - 1);
3340 if (PT == PT_Ptr) {
3341 const auto &Ptr = S.Stk.pop<Pointer>();
3342 assert(S.Stk.size() == StackSizeBefore);
3345 } else {
3346 // Pop the result from the stack and return success.
3347 TYPE_SWITCH(PT, S.Stk.discard<T>(););
3348 assert(S.Stk.size() == StackSizeBefore);
3350 }
3351 } else {
3352 // Jump to the end of the speculation, just after the actual EndSpeculation
3353 // op.
3354 S.PC = PCBefore + Offset - align(sizeof(Opcode));
3355
3356 // End the speculation manually since we didn't call EndSpeculation
3357 // naturally.
3358 EndSpeculation(S);
3359
3360 if (!S.inConstantContext())
3361 return Invalid(S, OpPC);
3362
3363 S.Stk.clearTo(StackSizeBefore);
3365 }
3366
3367 // We have already evaluated this speculation's EndSpeculation opcode.
3368 assert(S.SpeculationDepth == DepthBefore - 1);
3369
3370 return true;
3371}
3372
3373} // namespace interp
3374} // namespace clang
Defines the clang::ASTContext interface.
#define V(N, I)
Defines the clang::Expr interface and subclasses for C++ expressions.
static const FunctionDecl * getVirtualOperatorDelete(QualType T)
static PRESERVE_NONE bool RetValue(InterpState &S)
Definition Interp.cpp:52
static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK)
Definition Interp.cpp:194
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition Interp.cpp:221
static bool Jf(InterpState &S, CodePtr OpPC, int32_t Offset)
Definition Interp.cpp:73
static bool Jmp(InterpState &S, CodePtr OpPC, int32_t Offset)
Definition Interp.cpp:60
static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, const ValueDecl *D, AccessKinds AK=AK_Read)
Definition Interp.cpp:102
static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD, AccessKinds AK=AK_Read)
Definition Interp.cpp:152
static bool isModification(AccessKinds AK)
Definition Interp.cpp:147
#define MUSTTAIL
Definition Interp.cpp:46
static void noteValueLocation(InterpState &S, const Block *B)
Definition Interp.cpp:88
static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, const ValueDecl *VD)
Definition Interp.cpp:81
static bool Jt(InterpState &S, CodePtr OpPC, int32_t Offset)
Definition Interp.cpp:65
#define PRESERVE_NONE
Definition Interp.h:50
static StringRef getIdentifier(const Token &Tok)
#define TYPE_SWITCH_ALLOC(Expr, B)
Definition PrimType.h:297
#define TYPE_SWITCH(Expr, B)
Definition PrimType.h:223
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:122
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
bool hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType U) const
Determine whether two function types are the same, ignoring exception specifications in cases where t...
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
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.
const clang::PrintingPolicy & getPrintingPolicy() const
Definition ASTContext.h:876
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
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:942
CanQualType getCanonicalTagType(const TagDecl *TD) const
QualType getElementType() const
Definition TypeBase.h:3848
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
AccessSpecifier Access
The access along this inheritance path.
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
paths_iterator begin()
paths_iterator end()
Represents a C++ destructor within a class.
Definition DeclCXX.h:2902
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2145
bool isVirtual() const
Definition DeclCXX.h:2200
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition DeclCXX.h:522
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2954
Expr * getCallee()
Definition Expr.h:3101
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3145
Expr ** getArgs()
Retrieve the call arguments.
Definition Expr.h:3148
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
Definition Expr.cpp:1609
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1281
ValueDecl * getDecl()
Definition Expr.h:1349
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool isInvalidDecl() const
Definition DeclBase.h:596
SourceLocation getLocation() const
Definition DeclBase.h:447
bool hasAttr() const
Definition DeclBase.h:585
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition DeclBase.h:435
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Represents an enum.
Definition Decl.h:4145
unsigned getNumNegativeBits() const
Returns the width in bits required to store all the negative enumerators of this enum.
Definition Decl.h:4355
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:5252
This represents one expression.
Definition Expr.h:112
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
QualType getType() const
Definition Expr.h:144
LangOptions::FPExceptionModeKind getExceptionMode() const
static FPOptions getFromOpaqueInt(storage_type Value)
RoundingMode getRoundingMode() const
Represents a member of a struct/union/class.
Definition Decl.h:3294
Represents a function declaration or definition.
Definition Decl.h:2058
QualType getReturnType() const
Definition Decl.h:2975
StorageClass getStorageClass() const
Returns the storage class as written in the source.
Definition Decl.h:3018
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
Definition Decl.h:2596
bool isPureVirtual() const
Whether this virtual function is pure, i.e.
Definition Decl.h:2479
bool isUsableAsGlobalAllocationFunctionInConstantEvaluation(UnsignedOrNone *AlignmentParam=nullptr, bool *IsNothrow=nullptr) const
Determines whether this function is one of the replaceable global allocation functions described in i...
Definition Decl.cpp:3469
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3187
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:3234
@ FPE_Ignore
Assume that floating-point exceptions are masked.
This represents a decl that may have a name.
Definition Decl.h:274
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:295
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
Definition TypeBase.h:8588
void addConst()
Add the const type qualifier to this QualType.
Definition TypeBase.h:1172
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition TypeBase.h:8577
Represents a struct/union/class.
Definition Decl.h:4459
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:343
TagDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition Decl.cpp:4962
uint64_t getPointerWidth(LangAS AddrSpace) const
Return the width of pointers on this target, for the specified address space.
Definition TargetInfo.h:496
The base class of the type hierarchy.
Definition TypeBase.h:1879
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isArrayType() const
Definition TypeBase.h:8840
bool isPointerType() const
Definition TypeBase.h:8741
CanQualType getCanonicalTypeUnqualified() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9157
bool isReferenceType() const
Definition TypeBase.h:8765
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition TypeBase.h:9235
bool isAnyComplexType() const
Definition TypeBase.h:8876
bool isPointerOrReferenceType() const
Definition TypeBase.h:8745
bool isRecordType() const
Definition TypeBase.h:8868
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:932
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
Definition Decl.h:1593
bool isStaticDataMember() const
Determines whether this is a static data member.
Definition Decl.h:1306
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:44
unsigned getSize() const
Returns the size of the block.
Definition InterpBlock.h:87
const T & deref() const
bool isExtern() const
Checks if the block is extern.
Definition InterpBlock.h:77
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition InterpBlock.h:73
bool isStatic() const
Checks if the block has static storage duration.
Definition InterpBlock.h:79
bool isTemporary() const
Checks if the block is temporary.
Definition InterpBlock.h:81
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
bool isInitialized() const
Returns whether the data of this block has been initialized via invoking the Ctor func.
Definition InterpBlock.h:92
bool isDynamic() const
Definition InterpBlock.h:83
UnsignedOrNone getDeclID() const
Returns the declaration ID.
Definition InterpBlock.h:89
bool isDummy() const
Definition InterpBlock.h:84
unsigned getEvalID() const
The Evaluation ID this block was created in.
Definition InterpBlock.h:94
bool isWeak() const
Definition InterpBlock.h:82
bool isAccessible() const
Pointer into the code segment.
Definition Source.h:31
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Definition Source.h:60
Compilation context for expressions.
Definition Compiler.h:119
unsigned collectBaseOffset(const RecordDecl *BaseDecl, const RecordDecl *DerivedDecl) const
Definition Context.cpp:745
const Record * getRecord(const RecordDecl *D) const
Definition Context.cpp:776
const Function * getOrCreateFunction(const FunctionDecl *FuncDecl)
Definition Context.cpp:612
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:107
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:465
const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, const CXXMethodDecl *InitialFunction) const
Definition Context.cpp:576
Manages dynamic memory allocations done during bytecode interpretation.
std::optional< Form > getAllocationForm(const Expr *Source) const
Checks whether the allocation done at the given source is an array allocation.
bool deallocate(const Expr *Source, const Block *BlockToDelete)
Deallocate the given source+block combination.
Wrapper around fixed point types.
Definition FixedPoint.h:23
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition FixedPoint.h:81
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition Floating.h:35
bool isFinite() const
Definition Floating.h:151
APFloat::opStatus convertToInteger(APSInt &Result) const
Definition Floating.h:71
APFloat getAPFloat() const
Definition Floating.h:64
Base class for stack frames, shared between VM and walker.
Definition Frame.h:25
Bytecode function.
Definition Function.h:99
bool hasExplicitThisPointer() const
Definition Function.h:227
Scope & getScope(unsigned Idx)
Returns a specific scope.
Definition Function.h:174
CodePtr getCodeBegin() const
Returns a pointer to the start of the code.
Definition Function.h:129
bool isDestructor() const
Checks if the function is a destructor.
Definition Function.h:197
bool isVirtual() const
Checks if the function is virtual.
Definition Function.h:184
bool hasNonNullAttr() const
Definition Function.h:158
bool isFullyCompiled() const
Checks if the function is fully done compiling.
Definition Function.h:224
bool isConstructor() const
Checks if the function is a constructor.
Definition Function.h:189
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition Function.h:134
bool hasBody() const
Checks if the function already has a body attached.
Definition Function.h:235
bool isConstexpr() const
Definition Function.h:186
unsigned getWrittenArgSize() const
Definition Function.h:251
unsigned getArgSize() const
Returns the size of the argument stack.
Definition Function.h:126
bool isLambdaStaticInvoker() const
Returns whether this function is a lambda static invoker, which we generate custom byte code for.
Definition Function.h:205
bool isValid() const
Checks if the function is valid to call.
Definition Function.h:181
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition IntegralAP.h:36
void copy(const APInt &V)
Definition IntegralAP.h:78
Wrapper around numeric types.
Definition Integral.h:69
static std::enable_if_t<!std::is_same_v< ValT, IntegralKind >, Integral > from(ValT V, unsigned NumBits=0)
Definition Integral.h:320
Frame storing local variables.
Definition InterpFrame.h:27
static void free(InterpFrame *F)
Definition InterpFrame.h:62
const Expr * getExpr(CodePtr PC) const
InterpFrame * Caller
The frame of the previous function.
Definition InterpFrame.h:30
SourceInfo getSource(CodePtr PC) const
Map a location to a source.
Block * getLocalBlock(unsigned Offset) const
SourceLocation getLocation(CodePtr PC) const
const Pointer & getThis() const
Returns the 'this' pointer.
const Function * getFunction() const
Returns the current function.
Definition InterpFrame.h:93
SourceRange getRange(CodePtr PC) const
unsigned getArgSize() const
bool isRoot() const
Checks if the frame is a root frame - return should quit the interpreter.
Pointer getLocalPointer(unsigned Offset) const
Returns a pointer to a local variables.
unsigned getDepth() const
void destroy(unsigned Idx)
Invokes the destructors for a scope.
static size_t allocSize(const Function *F)
Returns the number of bytes needed to allocate an InterpFrame for the given function.
Definition InterpFrame.h:51
void clearTo(size_t NewSize)
T pop()
Returns the value from the top of the stack and removes it.
Definition InterpStack.h:39
void push(Tys &&...Args)
Constructs a value in place on the top of the stack.
Definition InterpStack.h:33
size_t size() const
Returns the size of the stack in bytes.
Definition InterpStack.h:78
void discard()
Discards the top value from the stack.
Definition InterpStack.h:50
T & peek() const
Returns a reference to the value on the top of the stack.
Definition InterpStack.h:63
Interpreter context.
Definition InterpState.h:43
bool lifetimeStartedInEvaluation(const Block *B) const
Context & getContext() const
Definition InterpState.h:78
bool initializingBlock(const Block *B) const
DynamicAllocator & getAllocator()
Definition InterpState.h:82
Context & Ctx
Interpreter Context.
bool noteStep(CodePtr OpPC)
Note that a step has been executed.
const unsigned EvalID
ID identifying this evaluation.
InterpStack & Stk
Temporary stack.
bool checkingConstantDestruction() const
Return if we're checking if a global variable has a constant destructor.
const VarDecl * EvaluatingDecl
Declaration we're initializing/evaluting, if any.
InterpFrame * Current
The current frame.
const CXXRecordDecl ** allocMemberPointerPath(unsigned Length)
llvm::SmallVector< PtrView > InitializingPtrs
List of blocks we're currently running either constructors or destructors for.
T allocAP(unsigned BitWidth)
StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const
Program & P
Reference to the module containing all bytecode.
unsigned getPathLength() const
Return the length of the cast path.
PrimType value_or(PrimType PT) const
Definition PrimType.h:88
A pointer to a memory block, live or dead.
Definition Pointer.h:405
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition Pointer.h:494
UnsignedOrNone getDeclID() const
Returns the declaration ID.
Definition Pointer.h:788
Pointer stripBaseCasts() const
Strip base casts from this Pointer.
Definition Pointer.h:982
bool isVolatile() const
Checks if an object or a subfield is volatile.
Definition Pointer.h:781
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:557
bool isStatic() const
Checks if the storage is static.
Definition Pointer.h:706
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition Pointer.h:721
bool inUnion() const
Definition Pointer.h:623
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:857
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition Pointer.h:471
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition Pointer.h:762
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition Pointer.h:487
bool isExtern() const
Checks if the storage is extern.
Definition Pointer.h:700
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:824
bool isActive() const
Checks if the object is active.
Definition Pointer.h:752
bool isConst() const
Checks if an object or a subfield is mutable.
Definition Pointer.h:769
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition Pointer.h:481
bool isMutable() const
Checks if the field is mutable.
Definition Pointer.h:732
bool isConstInMutable() const
Definition Pointer.h:774
unsigned getNumElems() const
Returns the number of elements.
Definition Pointer.h:808
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition Pointer.h:636
const TypeidPointer & asTypeidPointer() const
Definition Pointer.h:674
bool isIntegralPointer() const
Definition Pointer.h:680
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:574
bool isArrayElement() const
Checks if the pointer points to an array.
Definition Pointer.h:642
bool pointsToStringLiteral() const
Definition Pointer.cpp:876
void initialize() const
Initializes a field.
Definition Pointer.h:920
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition Pointer.h:615
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:522
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition Pointer.h:559
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition Pointer.h:797
bool isTypeidPointer() const
Definition Pointer.h:682
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition Pointer.cpp:544
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:508
bool isConstexprUnknown() const
Definition Pointer.h:898
const IntPointer & asIntPointer() const
Definition Pointer.h:666
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:649
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:536
void activate() const
Activates a field.
Definition Pointer.h:951
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition Pointer.cpp:818
bool isOnePastEnd() const
Checks if the index is one past end.
Definition Pointer.h:832
uint64_t getIntegerRepresentation() const
Definition Pointer.h:453
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition Pointer.h:846
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:693
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition Pointer.h:501
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition Pointer.h:854
void startLifetime() const
Start the lifetime of this pointer.
Definition Pointer.h:967
bool isBlockPointer() const
Definition Pointer.h:679
const FunctionPointer & asFunctionPointer() const
Definition Pointer.h:670
const Block * block() const
Definition Pointer.h:814
bool isFunctionPointer() const
Definition Pointer.h:681
Pointer getDeclPtr() const
Definition Pointer.h:590
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:564
PtrView view() const
Definition Pointer.h:461
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition Pointer.h:655
Lifetime getLifetime() const
Definition Pointer.h:957
bool isField() const
Checks if the item is a field in an object.
Definition Pointer.h:528
const Record * getRecord() const
Returns the record descriptor of a class.
Definition Pointer.h:685
UnsignedOrNone getCurrentDecl() const
Returns the current declaration ID.
Definition Program.h:163
Structure/Class descriptor.
Definition Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition Record.h:65
unsigned getNumVirtualBases() const
Definition Record.h:126
llvm::iterator_range< LocalVectorTy::const_reverse_iterator > locals_reverse() const
Definition Function.h:57
Describes the statement/declaration an opcode was generated from.
Definition Source.h:77
bool checkingForUndefinedBehavior() const
Are we checking an expression for overflow?
Definition State.h:125
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition State.cpp:85
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation could not be folded (FF => FoldFailure)
Definition State.cpp:36
ASTContext & getASTContext() const
Definition State.h:92
bool noteUndefinedBehavior() const
Note that we hit something that was technically undefined behavior, but that we can evaluate past it ...
Definition State.h:114
OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation does not produce a C++11 core constant expression.
Definition State.cpp:59
const LangOptions & getLangOpts() const
Definition State.h:93
bool checkingPotentialConstantExpression() const
Are we checking whether the expression is a potential constant expression?
Definition State.h:121
Defines the clang::TargetInfo interface.
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS, const Pointer &RHS)
Definition Interp.cpp:2852
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition Interp.cpp:1640
bool GetMemberPtrBase(InterpState &S)
Definition Interp.cpp:3142
bool PseudoDtor(InterpState &S, CodePtr OpPC)
Ends the lifetime of the pop'd pointer.
Definition Interp.cpp:2524
static bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Definition Interp.cpp:1155
static constexpr bool OpReturns(Opcode Op)
Definition Interp.cpp:3229
const InterpFn InterpFunctions[]
Definition Interp.cpp:3251
static bool diagnoseCallableDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *DiagDecl)
Definition Interp.cpp:1051
bool GetTypeid(InterpState &S, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
Definition Interp.cpp:2803
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition Interp.cpp:2754
static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition Interp.cpp:687
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition Interp.cpp:2741
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition Interp.cpp:1043
bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD)
Opcode. Check if the function decl can be called at compile time.
Definition Interp.cpp:1790
bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
static bool appendToMemberPointer(InterpState &S, const MemberPointer &MemberPtr, int32_t BaseOffset, const RecordDecl *BaseDecl, bool IsDerivedMember)
Definition Interp.cpp:3094
static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Definition Interp.cpp:1131
bool StartThisLifetime(InterpState &S)
Definition Interp.cpp:2468
void cleanupAfterFunctionCall(InterpState &S, const Function *Func)
Definition Interp.cpp:267
static bool runRecordDestructor(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const Descriptor *Desc)
Definition Interp.cpp:1350
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc, AccessKinds AK)
Checks if the Descriptor is of a constexpr or const global variable.
Definition Interp.cpp:463
bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType)
Definition Interp.cpp:2808
bool LT(InterpState &S, CodePtr OpPC)
Definition Interp.h:1530
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:576
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:1248
static void setLifeStateRecurse(PtrView Ptr, Lifetime L)
Definition Interp.cpp:2492
bool PushIgnoreDiags(InterpState &S)
Definition Interp.h:3642
bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B)
Checks a direct load of a primitive value from a global or local variable.
Definition Interp.cpp:827
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:1290
bool EndLifetime(InterpState &S, CodePtr OpPC)
Ends the lifetime of the peek'd pointer.
Definition Interp.cpp:2514
static bool getDynamicDecl(InterpState &S, CodePtr OpPC, PtrView TypePtr, const CXXRecordDecl *&DynamicDecl)
Definition Interp.cpp:2009
bool CastMemberPtrDerivedPop(InterpState &S, int32_t Off, const RecordDecl *BaseDecl)
BaseToDerivedMemberPointer.
Definition Interp.cpp:3124
static DynamicCastResult findRecordBase(const ASTContext &Ctx, const Record *R, QualType Needle)
Definition Interp.cpp:2093
static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B)
Definition Interp.cpp:810
static void copyPrimitiveMemory(InterpState &S, PtrView Ptr, PrimType T)
Definition Interp.cpp:2903
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
Definition Interp.cpp:2713
static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B)
Definition Interp.cpp:1377
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
Definition Interp.cpp:1635
bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK, bool WillActivate)
Definition Interp.cpp:324
static bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
Definition Interp.cpp:1328
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition Interp.cpp:565
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)
Definition Interp.cpp:2692
bool PopIgnoreDiags(InterpState &S)
Definition Interp.h:3654
bool GetMemberPtrDecl(InterpState &S)
Definition Interp.cpp:3152
bool handleReference(InterpState &S, CodePtr OpPC, Block *B)
Definition Interp.cpp:2784
bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType, bool SrcIsVoidPtr)
Definition Interp.cpp:1805
bool CopyMemberPtrPath(InterpState &S, const RecordDecl *Entry, bool IsDerived)
Just append the given Entry to the MemberPointer's path.
Definition Interp.cpp:3179
static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Off)
Definition Interp.cpp:1594
static void startLifetimeRecurse(PtrView Ptr)
Definition Interp.cpp:2443
static bool hasVirtualDestructor(QualType T)
Definition Interp.cpp:1408
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
Definition Interp.cpp:889
static bool getBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Off, bool NullOK)
Definition Interp.cpp:1645
static void finishGlobalRecurse(InterpState &S, PtrView Ptr)
Definition Interp.cpp:2949
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition PrimType.h:201
bool CheckBCPResult(InterpState &S, const Pointer &Ptr)
Definition Interp.cpp:304
PRESERVE_NONE bool EndSpeculation(InterpState &S)
Definition Interp.h:3686
bool diagnoseShiftFailure(InterpState &S, CodePtr OpPC, ShiftFailure Failure, const APSInt *Value, unsigned Bits)
Definition Interp.cpp:240
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
Definition Interp.cpp:1239
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition Interp.cpp:433
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK, const Type *TargetType)
Definition Interp.cpp:1683
bool DiagTypeid(InterpState &S, CodePtr OpPC)
Definition Interp.cpp:2844
bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition Interp.cpp:734
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
Definition Interp.cpp:966
static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, const Pointer &ThisPtr)
Definition Interp.cpp:1722
llvm::APInt APInt
Definition FixedPoint.h:19
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
Definition Interp.cpp:1516
bool isConstexprUnknown(const Block *B)
Definition Interp.cpp:292
bool StartThisLifetime1(InterpState &S)
Definition Interp.cpp:2479
bool RVOPtr(InterpState &S)
Definition Interp.h:3207
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
Definition Interp.cpp:1295
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition Interp.cpp:533
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:1266
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:1219
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool IsCtor, bool IsDtor)
Definition Interp.cpp:1030
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, uint32_t BuiltinID)
Interpret a builtin function.
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition Interp.cpp:1861
constexpr bool needsAlloc()
Definition PrimType.h:131
bool(*)(InterpState &) PRESERVE_NONE InterpFn
Definition Interp.cpp:3249
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition Interp.cpp:2705
bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK)
Checks if a pointer is a dummy pointer.
Definition Interp.cpp:1310
static bool diagnoseOutOfLifetimeDestroy(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition Interp.cpp:1746
static bool floatAPCast(InterpState &S, CodePtr OpPC, const Floating &F, uint32_t BitWidth, uint32_t FPOI)
Definition Interp.cpp:3196
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:2541
bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition Interp.cpp:1762
bool CheckRange(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition Interp.cpp:544
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
Definition Interp.cpp:1537
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition Interp.cpp:425
bool CheckFloatStatus(InterpState &S, CodePtr OpPC, APFloat::opStatus Status, FPOptions FPO)
Check if the given floating-point evaluation status is allowed for compile-time constant folding duri...
Definition Interp.cpp:1183
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition Interp.cpp:1674
static void compileFunction(InterpState &S, const Function *Func)
Definition Interp.cpp:1850
bool CheckThis(InterpState &S, CodePtr OpPC)
Checks the 'this' pointer.
Definition Interp.cpp:1166
bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition Interp.cpp:3222
bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth)
Definition Interp.cpp:2736
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition Interp.cpp:3044
bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK)
Checks if a pointer points to a mutable field.
Definition Interp.cpp:660
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition PrimType.cpp:24
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
Definition Interp.cpp:1415
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
Definition Interp.cpp:2645
bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE, uint32_t BuiltinID)
Definition Interp.cpp:2370
bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B)
Definition Interp.cpp:858
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
Definition Interp.cpp:406
static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT, const Block *B, AccessKinds AK)
Definition Interp.cpp:793
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool WillBeActivated)
Checks if a value can be stored in a block.
Definition Interp.cpp:999
bool FinishInitGlobal(InterpState &S)
Definition Interp.cpp:2997
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK)
Definition Interp.cpp:1678
llvm::BitVector collectNonNullArgs(const FunctionDecl *F, ArrayRef< const Expr * > Args)
static bool castBackMemberPointer(InterpState &S, const MemberPointer &MemberPtr, int32_t BaseOffset, const RecordDecl *BaseDecl)
Definition Interp.cpp:3062
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
Definition Interp.cpp:2381
bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
Definition Interp.cpp:3216
bool MarkDestroyed(InterpState &S, CodePtr OpPC)
Definition Interp.cpp:2532
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition Interp.cpp:2275
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition Interp.cpp:603
bool Interpret(InterpState &S)
Interpreter entry point.
Definition Interp.cpp:3266
bool GetMemberPtr(InterpState &S, const ValueDecl *D)
Definition Interp.cpp:3137
static PRESERVE_NONE bool BCP(InterpState &S, CodePtr OpPC, int32_t Offset, PrimType PT)
This is used to implement speculative execution via __builtin_constant_p when we generate bytecode.
Definition Interp.cpp:3301
bool CastMemberPtrBasePop(InterpState &S, int32_t Off, const RecordDecl *BaseDecl)
DerivedToBaseMemberPointer.
Definition Interp.cpp:3112
llvm::APSInt APSInt
Definition FixedPoint.h:20
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
Definition Interp.cpp:3009
bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestTypePtr, bool IsReferenceCast)
Definition Interp.cpp:2110
static bool diagnoseTypeIdField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned Offset)
Definition Interp.cpp:1569
RangeSelector merge(RangeSelector First, RangeSelector Second)
Selects the merge of the two ranges, i.e.
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Ambiguous
Name lookup results in an ambiguity; use getAmbiguityKind to figure out what kind of ambiguity we hav...
Definition Lookup.h:64
@ Success
Annotation was successful.
Definition Parser.h:65
@ AS_private
Definition Specifiers.h:127
@ SC_Extern
Definition Specifiers.h:252
CheckSubobjectKind
The order of this enum is important for diagnostics.
Definition State.h:44
@ CSK_Derived
Definition State.h:46
@ CSK_Base
Definition State.h:45
@ CSK_Field
Definition State.h:47
@ Result
The result type of a method or function.
Definition TypeBase.h:906
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
Definition State.h:28
@ AK_TypeId
Definition State.h:36
@ AK_Construct
Definition State.h:37
@ AK_Increment
Definition State.h:32
@ AK_DynamicCast
Definition State.h:35
@ AK_Read
Definition State.h:29
@ AK_Assign
Definition State.h:31
@ AK_MemberCall
Definition State.h:34
@ AK_Destroy
Definition State.h:38
@ AK_Decrement
Definition State.h:33
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
@ Off
Never emit colors regardless of the output stream.
U cast(CodeGen::Address addr)
Definition Address.h:327
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 int32_t
A quantity in bits.
Describes a memory block created by an allocation site.
Definition Descriptor.h:122
const bool IsConst
Flag indicating if the block is mutable.
Definition Descriptor.h:161
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:258
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:272
bool hasTrivialDtor() const
Whether variables of this descriptor need their destructor called or not.
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition Descriptor.h:265
const ValueDecl * asValueDecl() const
Definition Descriptor.h:214
QualType getType() const
const Decl * asDecl() const
Definition Descriptor.h:210
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition Descriptor.h:155
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition Descriptor.h:255
SourceLocation getLocation() const
QualType getDataType(const ASTContext &Ctx) const
unsigned getElemDataSize() const
Returns the element data size, i.e.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:263
const VarDecl * asVarDecl() const
Definition Descriptor.h:218
PrimType getPrimType() const
Definition Descriptor.h:240
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:277
const bool IsTemporary
Flag indicating if the block is a temporary.
Definition Descriptor.h:165
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:153
const Expr * asExpr() const
Definition Descriptor.h:211
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:275
Descriptor used for global variables.
Definition Descriptor.h:49
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:67
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
Definition Pointer.cpp:1148
PtrView atField(unsigned Offset) const
Definition Pointer.h:264
const Record * getRecord() const
Definition Pointer.h:156
const Descriptor * getFieldDesc() const
Definition Pointer.h:81
const FieldDecl * getField() const
Definition Pointer.h:161
PtrView atIndex(unsigned Idx) const
Definition Pointer.h:200
void startLifetime() const
Definition Pointer.h:321
PtrView narrow() const
Definition Pointer.h:91
const Block * block() const
Definition Pointer.h:56
bool isMutable() const
Definition Pointer.h:50
QualType getType() const
Definition Pointer.h:269
bool isOnePastEnd() const
Definition Pointer.h:191
bool isConst() const
Definition Pointer.h:64
bool isRoot() const
Definition Pointer.h:60
void setLifeState(Lifetime L) const
Definition Pointer.cpp:636
Lifetime getLifetime() const
Definition Pointer.cpp:617
PtrView getBase() const
Definition Pointer.h:259
bool isActive() const
Definition Pointer.h:46
bool isZeroSizeArray() const
Definition Pointer.h:49
bool isLive() const
Definition Pointer.h:44
T & deref() const
Definition Pointer.h:235
PtrView stripBaseCasts() const
Definition Pointer.h:144