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