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