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