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