1 //===--- Interp.h - 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 // Definition of the interpreter state and entry point.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14 #define LLVM_CLANG_AST_INTERP_INTERP_H
15
16 #include "../ExprConstShared.h"
17 #include "Boolean.h"
18 #include "DynamicAllocator.h"
19 #include "Floating.h"
20 #include "Function.h"
21 #include "FunctionPointer.h"
22 #include "InterpFrame.h"
23 #include "InterpStack.h"
24 #include "InterpState.h"
25 #include "MemberPointer.h"
26 #include "Opcode.h"
27 #include "PrimType.h"
28 #include "Program.h"
29 #include "State.h"
30 #include "clang/AST/ASTContext.h"
31 #include "clang/AST/Expr.h"
32 #include "llvm/ADT/APFloat.h"
33 #include "llvm/ADT/APSInt.h"
34 #include <type_traits>
35
36 namespace clang {
37 namespace interp {
38
39 using APSInt = llvm::APSInt;
40
41 /// Convert a value to an APValue.
42 template <typename T>
ReturnValue(const InterpState & S,const T & V,APValue & R)43 bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
44 R = V.toAPValue(S.getCtx());
45 return true;
46 }
47
48 /// Checks if the variable has externally defined storage.
49 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
50
51 /// Checks if the array is offsetable.
52 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
53
54 /// Checks if a pointer is live and accessible.
55 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
56 AccessKinds AK);
57
58 /// Checks if a pointer is a dummy pointer.
59 bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
60 AccessKinds AK);
61
62 /// Checks if a pointer is null.
63 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64 CheckSubobjectKind CSK);
65
66 /// Checks if a pointer is in range.
67 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68 AccessKinds AK);
69
70 /// Checks if a field from which a pointer is going to be derived is valid.
71 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
72 CheckSubobjectKind CSK);
73
74 /// Checks if Ptr is a one-past-the-end pointer.
75 bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
76 CheckSubobjectKind CSK);
77
78 /// Checks if the dowcast using the given offset is possible with the given
79 /// pointer.
80 bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
81 uint32_t Offset);
82
83 /// Checks if a pointer points to const storage.
84 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85
86 /// Checks if the Descriptor is of a constexpr or const global variable.
87 bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
88
89 /// Checks if a pointer points to a mutable field.
90 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
91
92 /// Checks if a value can be loaded from a block.
93 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
94 AccessKinds AK = AK_Read);
95
96 bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
97 AccessKinds AK);
98 /// Check if a global variable is initialized.
99 bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
100
101 /// Checks if a value can be stored in a block.
102 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
103
104 /// Checks if a method can be invoked on an object.
105 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
106
107 /// Checks if a value can be initialized.
108 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
109
110 /// Checks if a method can be called.
111 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
112
113 /// Checks if calling the currently active function would exceed
114 /// the allowed call depth.
115 bool CheckCallDepth(InterpState &S, CodePtr OpPC);
116
117 /// Checks the 'this' pointer.
118 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
119
120 /// Checks if a method is pure virtual.
121 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
122
123 /// Checks if all the arguments annotated as 'nonnull' are in fact not null.
124 bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
125 const CallExpr *CE, unsigned ArgSize);
126
127 /// Checks if dynamic memory allocation is available in the current
128 /// language mode.
129 bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
130
131 /// Diagnose mismatched new[]/delete or new/delete[] pairs.
132 bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
133 bool DeleteIsArray, const Descriptor *D,
134 const Expr *NewExpr);
135
136 /// Check the source of the pointer passed to delete/delete[] has actually
137 /// been heap allocated by us.
138 bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
139 const Pointer &Ptr);
140
141 /// Sets the given integral value to the pointer, which is of
142 /// a std::{weak,partial,strong}_ordering type.
143 bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
144 const Pointer &Ptr, const APSInt &IntValue);
145
146 /// Copy the contents of Src into Dest.
147 bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
148
149 /// Checks if the shift operation is legal.
150 template <typename LT, typename RT>
CheckShift(InterpState & S,CodePtr OpPC,const LT & LHS,const RT & RHS,unsigned Bits)151 bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
152 unsigned Bits) {
153 if (RHS.isNegative()) {
154 const SourceInfo &Loc = S.Current->getSource(OpPC);
155 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
156 if (!S.noteUndefinedBehavior())
157 return false;
158 }
159
160 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
161 // the shifted type.
162 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
163 const Expr *E = S.Current->getExpr(OpPC);
164 const APSInt Val = RHS.toAPSInt();
165 QualType Ty = E->getType();
166 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
167 if (!S.noteUndefinedBehavior())
168 return false;
169 }
170
171 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
172 const Expr *E = S.Current->getExpr(OpPC);
173 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
174 // operand, and must not overflow the corresponding unsigned type.
175 if (LHS.isNegative()) {
176 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
177 if (!S.noteUndefinedBehavior())
178 return false;
179 } else if (LHS.toUnsigned().countLeadingZeros() <
180 static_cast<unsigned>(RHS)) {
181 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
182 if (!S.noteUndefinedBehavior())
183 return false;
184 }
185 }
186
187 // C++2a [expr.shift]p2: [P0907R4]:
188 // E1 << E2 is the unique value congruent to
189 // E1 x 2^E2 module 2^N.
190 return true;
191 }
192
193 /// Checks if Div/Rem operation on LHS and RHS is valid.
194 template <typename T>
CheckDivRem(InterpState & S,CodePtr OpPC,const T & LHS,const T & RHS)195 bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
196 if (RHS.isZero()) {
197 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
198 if constexpr (std::is_same_v<T, Floating>) {
199 S.CCEDiag(Op, diag::note_expr_divide_by_zero)
200 << Op->getRHS()->getSourceRange();
201 return true;
202 }
203
204 S.FFDiag(Op, diag::note_expr_divide_by_zero)
205 << Op->getRHS()->getSourceRange();
206 return false;
207 }
208
209 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
210 APSInt LHSInt = LHS.toAPSInt();
211 SmallString<32> Trunc;
212 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
213 const SourceInfo &Loc = S.Current->getSource(OpPC);
214 const Expr *E = S.Current->getExpr(OpPC);
215 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
216 return false;
217 }
218 return true;
219 }
220
221 template <typename SizeT>
CheckArraySize(InterpState & S,CodePtr OpPC,SizeT * NumElements,unsigned ElemSize,bool IsNoThrow)222 bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
223 unsigned ElemSize, bool IsNoThrow) {
224 // FIXME: Both the SizeT::from() as well as the
225 // NumElements.toAPSInt() in this function are rather expensive.
226
227 // FIXME: GH63562
228 // APValue stores array extents as unsigned,
229 // so anything that is greater that unsigned would overflow when
230 // constructing the array, we catch this here.
231 SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
232 if (NumElements->toAPSInt().getActiveBits() >
233 ConstantArrayType::getMaxSizeBits(S.getCtx()) ||
234 *NumElements > MaxElements) {
235 if (!IsNoThrow) {
236 const SourceInfo &Loc = S.Current->getSource(OpPC);
237 S.FFDiag(Loc, diag::note_constexpr_new_too_large)
238 << NumElements->toDiagnosticString(S.getCtx());
239 }
240 return false;
241 }
242 return true;
243 }
244
245 /// Checks if the result of a floating-point operation is valid
246 /// in the current context.
247 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
248 APFloat::opStatus Status);
249
250 /// Checks why the given DeclRefExpr is invalid.
251 bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
252
253 /// Interpreter entry point.
254 bool Interpret(InterpState &S, APValue &Result);
255
256 /// Interpret a builtin function.
257 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
258 const CallExpr *Call);
259
260 /// Interpret an offsetof operation.
261 bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
262 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
263
264 inline bool Invalid(InterpState &S, CodePtr OpPC);
265
266 enum class ArithOp { Add, Sub };
267
268 //===----------------------------------------------------------------------===//
269 // Returning values
270 //===----------------------------------------------------------------------===//
271
272 void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
273
274 template <PrimType Name, class T = typename PrimConv<Name>::T>
Ret(InterpState & S,CodePtr & PC,APValue & Result)275 bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
276 const T &Ret = S.Stk.pop<T>();
277
278 // Make sure returned pointers are live. We might be trying to return a
279 // pointer or reference to a local variable.
280 // Just return false, since a diagnostic has already been emitted in Sema.
281 if constexpr (std::is_same_v<T, Pointer>) {
282 // FIXME: We could be calling isLive() here, but the emitted diagnostics
283 // seem a little weird, at least if the returned expression is of
284 // pointer type.
285 // Null pointers are considered live here.
286 if (!Ret.isZero() && !Ret.isLive())
287 return false;
288 }
289
290 assert(S.Current);
291 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
292 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
293 cleanupAfterFunctionCall(S, PC);
294
295 if (InterpFrame *Caller = S.Current->Caller) {
296 PC = S.Current->getRetPC();
297 delete S.Current;
298 S.Current = Caller;
299 S.Stk.push<T>(Ret);
300 } else {
301 delete S.Current;
302 S.Current = nullptr;
303 if (!ReturnValue<T>(S, Ret, Result))
304 return false;
305 }
306 return true;
307 }
308
RetVoid(InterpState & S,CodePtr & PC,APValue & Result)309 inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
310 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
311
312 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
313 cleanupAfterFunctionCall(S, PC);
314
315 if (InterpFrame *Caller = S.Current->Caller) {
316 PC = S.Current->getRetPC();
317 delete S.Current;
318 S.Current = Caller;
319 } else {
320 delete S.Current;
321 S.Current = nullptr;
322 }
323 return true;
324 }
325
326 //===----------------------------------------------------------------------===//
327 // Add, Sub, Mul
328 //===----------------------------------------------------------------------===//
329
330 template <typename T, bool (*OpFW)(T, T, unsigned, T *),
331 template <typename U> class OpAP>
AddSubMulHelper(InterpState & S,CodePtr OpPC,unsigned Bits,const T & LHS,const T & RHS)332 bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
333 const T &RHS) {
334 // Fast path - add the numbers with fixed width.
335 T Result;
336 if (!OpFW(LHS, RHS, Bits, &Result)) {
337 S.Stk.push<T>(Result);
338 return true;
339 }
340
341 // If for some reason evaluation continues, use the truncated results.
342 S.Stk.push<T>(Result);
343
344 // Slow path - compute the result using another bit of precision.
345 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
346
347 // Report undefined behaviour, stopping if required.
348 const Expr *E = S.Current->getExpr(OpPC);
349 QualType Type = E->getType();
350 if (S.checkingForUndefinedBehavior()) {
351 SmallString<32> Trunc;
352 Value.trunc(Result.bitWidth())
353 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
354 /*UpperCase=*/true, /*InsertSeparators=*/true);
355 auto Loc = E->getExprLoc();
356 S.report(Loc, diag::warn_integer_constant_overflow)
357 << Trunc << Type << E->getSourceRange();
358 }
359
360 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
361
362 if (!S.noteUndefinedBehavior()) {
363 S.Stk.pop<T>();
364 return false;
365 }
366
367 return true;
368 }
369
370 template <PrimType Name, class T = typename PrimConv<Name>::T>
Add(InterpState & S,CodePtr OpPC)371 bool Add(InterpState &S, CodePtr OpPC) {
372 const T &RHS = S.Stk.pop<T>();
373 const T &LHS = S.Stk.pop<T>();
374 const unsigned Bits = RHS.bitWidth() + 1;
375 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
376 }
377
Addf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)378 inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
379 const Floating &RHS = S.Stk.pop<Floating>();
380 const Floating &LHS = S.Stk.pop<Floating>();
381
382 Floating Result;
383 auto Status = Floating::add(LHS, RHS, RM, &Result);
384 S.Stk.push<Floating>(Result);
385 return CheckFloatResult(S, OpPC, Result, Status);
386 }
387
388 template <PrimType Name, class T = typename PrimConv<Name>::T>
Sub(InterpState & S,CodePtr OpPC)389 bool Sub(InterpState &S, CodePtr OpPC) {
390 const T &RHS = S.Stk.pop<T>();
391 const T &LHS = S.Stk.pop<T>();
392 const unsigned Bits = RHS.bitWidth() + 1;
393 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
394 }
395
Subf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)396 inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
397 const Floating &RHS = S.Stk.pop<Floating>();
398 const Floating &LHS = S.Stk.pop<Floating>();
399
400 Floating Result;
401 auto Status = Floating::sub(LHS, RHS, RM, &Result);
402 S.Stk.push<Floating>(Result);
403 return CheckFloatResult(S, OpPC, Result, Status);
404 }
405
406 template <PrimType Name, class T = typename PrimConv<Name>::T>
Mul(InterpState & S,CodePtr OpPC)407 bool Mul(InterpState &S, CodePtr OpPC) {
408 const T &RHS = S.Stk.pop<T>();
409 const T &LHS = S.Stk.pop<T>();
410 const unsigned Bits = RHS.bitWidth() * 2;
411 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
412 }
413
Mulf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)414 inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
415 const Floating &RHS = S.Stk.pop<Floating>();
416 const Floating &LHS = S.Stk.pop<Floating>();
417
418 Floating Result;
419 auto Status = Floating::mul(LHS, RHS, RM, &Result);
420 S.Stk.push<Floating>(Result);
421 return CheckFloatResult(S, OpPC, Result, Status);
422 }
423
424 template <PrimType Name, class T = typename PrimConv<Name>::T>
Mulc(InterpState & S,CodePtr OpPC)425 inline bool Mulc(InterpState &S, CodePtr OpPC) {
426 const Pointer &RHS = S.Stk.pop<Pointer>();
427 const Pointer &LHS = S.Stk.pop<Pointer>();
428 const Pointer &Result = S.Stk.peek<Pointer>();
429
430 if constexpr (std::is_same_v<T, Floating>) {
431 APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
432 APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
433 APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
434 APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
435
436 APFloat ResR(A.getSemantics());
437 APFloat ResI(A.getSemantics());
438 HandleComplexComplexMul(A, B, C, D, ResR, ResI);
439
440 // Copy into the result.
441 Result.atIndex(0).deref<Floating>() = Floating(ResR);
442 Result.atIndex(0).initialize();
443 Result.atIndex(1).deref<Floating>() = Floating(ResI);
444 Result.atIndex(1).initialize();
445 Result.initialize();
446 } else {
447 // Integer element type.
448 const T &LHSR = LHS.atIndex(0).deref<T>();
449 const T &LHSI = LHS.atIndex(1).deref<T>();
450 const T &RHSR = RHS.atIndex(0).deref<T>();
451 const T &RHSI = RHS.atIndex(1).deref<T>();
452 unsigned Bits = LHSR.bitWidth();
453
454 // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
455 T A;
456 if (T::mul(LHSR, RHSR, Bits, &A))
457 return false;
458 T B;
459 if (T::mul(LHSI, RHSI, Bits, &B))
460 return false;
461 if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))
462 return false;
463 Result.atIndex(0).initialize();
464
465 // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
466 if (T::mul(LHSR, RHSI, Bits, &A))
467 return false;
468 if (T::mul(LHSI, RHSR, Bits, &B))
469 return false;
470 if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))
471 return false;
472 Result.atIndex(1).initialize();
473 Result.initialize();
474 }
475
476 return true;
477 }
478
479 template <PrimType Name, class T = typename PrimConv<Name>::T>
Divc(InterpState & S,CodePtr OpPC)480 inline bool Divc(InterpState &S, CodePtr OpPC) {
481 const Pointer &RHS = S.Stk.pop<Pointer>();
482 const Pointer &LHS = S.Stk.pop<Pointer>();
483 const Pointer &Result = S.Stk.peek<Pointer>();
484
485 if constexpr (std::is_same_v<T, Floating>) {
486 APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
487 APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
488 APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
489 APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
490
491 APFloat ResR(A.getSemantics());
492 APFloat ResI(A.getSemantics());
493 HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
494
495 // Copy into the result.
496 Result.atIndex(0).deref<Floating>() = Floating(ResR);
497 Result.atIndex(0).initialize();
498 Result.atIndex(1).deref<Floating>() = Floating(ResI);
499 Result.atIndex(1).initialize();
500 Result.initialize();
501 } else {
502 // Integer element type.
503 const T &LHSR = LHS.atIndex(0).deref<T>();
504 const T &LHSI = LHS.atIndex(1).deref<T>();
505 const T &RHSR = RHS.atIndex(0).deref<T>();
506 const T &RHSI = RHS.atIndex(1).deref<T>();
507 unsigned Bits = LHSR.bitWidth();
508 const T Zero = T::from(0, Bits);
509
510 if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&
511 Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {
512 const SourceInfo &E = S.Current->getSource(OpPC);
513 S.FFDiag(E, diag::note_expr_divide_by_zero);
514 return false;
515 }
516
517 // Den = real(RHS)² + imag(RHS)²
518 T A, B;
519 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B))
520 return false;
521 T Den;
522 if (T::add(A, B, Bits, &Den))
523 return false;
524
525 // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
526 T &ResultR = Result.atIndex(0).deref<T>();
527 T &ResultI = Result.atIndex(1).deref<T>();
528
529 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
530 return false;
531 if (T::add(A, B, Bits, &ResultR))
532 return false;
533 if (T::div(ResultR, Den, Bits, &ResultR))
534 return false;
535 Result.atIndex(0).initialize();
536
537 // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
538 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
539 return false;
540 if (T::sub(A, B, Bits, &ResultI))
541 return false;
542 if (T::div(ResultI, Den, Bits, &ResultI))
543 return false;
544 Result.atIndex(1).initialize();
545 Result.initialize();
546 }
547
548 return true;
549 }
550
551 /// 1) Pops the RHS from the stack.
552 /// 2) Pops the LHS from the stack.
553 /// 3) Pushes 'LHS & RHS' on the stack
554 template <PrimType Name, class T = typename PrimConv<Name>::T>
BitAnd(InterpState & S,CodePtr OpPC)555 bool BitAnd(InterpState &S, CodePtr OpPC) {
556 const T &RHS = S.Stk.pop<T>();
557 const T &LHS = S.Stk.pop<T>();
558
559 unsigned Bits = RHS.bitWidth();
560 T Result;
561 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
562 S.Stk.push<T>(Result);
563 return true;
564 }
565 return false;
566 }
567
568 /// 1) Pops the RHS from the stack.
569 /// 2) Pops the LHS from the stack.
570 /// 3) Pushes 'LHS | RHS' on the stack
571 template <PrimType Name, class T = typename PrimConv<Name>::T>
BitOr(InterpState & S,CodePtr OpPC)572 bool BitOr(InterpState &S, CodePtr OpPC) {
573 const T &RHS = S.Stk.pop<T>();
574 const T &LHS = S.Stk.pop<T>();
575
576 unsigned Bits = RHS.bitWidth();
577 T Result;
578 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
579 S.Stk.push<T>(Result);
580 return true;
581 }
582 return false;
583 }
584
585 /// 1) Pops the RHS from the stack.
586 /// 2) Pops the LHS from the stack.
587 /// 3) Pushes 'LHS ^ RHS' on the stack
588 template <PrimType Name, class T = typename PrimConv<Name>::T>
BitXor(InterpState & S,CodePtr OpPC)589 bool BitXor(InterpState &S, CodePtr OpPC) {
590 const T &RHS = S.Stk.pop<T>();
591 const T &LHS = S.Stk.pop<T>();
592
593 unsigned Bits = RHS.bitWidth();
594 T Result;
595 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
596 S.Stk.push<T>(Result);
597 return true;
598 }
599 return false;
600 }
601
602 /// 1) Pops the RHS from the stack.
603 /// 2) Pops the LHS from the stack.
604 /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
605 template <PrimType Name, class T = typename PrimConv<Name>::T>
Rem(InterpState & S,CodePtr OpPC)606 bool Rem(InterpState &S, CodePtr OpPC) {
607 const T &RHS = S.Stk.pop<T>();
608 const T &LHS = S.Stk.pop<T>();
609
610 if (!CheckDivRem(S, OpPC, LHS, RHS))
611 return false;
612
613 const unsigned Bits = RHS.bitWidth() * 2;
614 T Result;
615 if (!T::rem(LHS, RHS, Bits, &Result)) {
616 S.Stk.push<T>(Result);
617 return true;
618 }
619 return false;
620 }
621
622 /// 1) Pops the RHS from the stack.
623 /// 2) Pops the LHS from the stack.
624 /// 3) Pushes 'LHS / RHS' on the stack
625 template <PrimType Name, class T = typename PrimConv<Name>::T>
Div(InterpState & S,CodePtr OpPC)626 bool Div(InterpState &S, CodePtr OpPC) {
627 const T &RHS = S.Stk.pop<T>();
628 const T &LHS = S.Stk.pop<T>();
629
630 if (!CheckDivRem(S, OpPC, LHS, RHS))
631 return false;
632
633 const unsigned Bits = RHS.bitWidth() * 2;
634 T Result;
635 if (!T::div(LHS, RHS, Bits, &Result)) {
636 S.Stk.push<T>(Result);
637 return true;
638 }
639 return false;
640 }
641
Divf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)642 inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
643 const Floating &RHS = S.Stk.pop<Floating>();
644 const Floating &LHS = S.Stk.pop<Floating>();
645
646 if (!CheckDivRem(S, OpPC, LHS, RHS))
647 return false;
648
649 Floating Result;
650 auto Status = Floating::div(LHS, RHS, RM, &Result);
651 S.Stk.push<Floating>(Result);
652 return CheckFloatResult(S, OpPC, Result, Status);
653 }
654
655 //===----------------------------------------------------------------------===//
656 // Inv
657 //===----------------------------------------------------------------------===//
658
659 template <PrimType Name, class T = typename PrimConv<Name>::T>
Inv(InterpState & S,CodePtr OpPC)660 bool Inv(InterpState &S, CodePtr OpPC) {
661 using BoolT = PrimConv<PT_Bool>::T;
662 const T &Val = S.Stk.pop<T>();
663 const unsigned Bits = Val.bitWidth();
664 Boolean R;
665 Boolean::inv(BoolT::from(Val, Bits), &R);
666
667 S.Stk.push<BoolT>(R);
668 return true;
669 }
670
671 //===----------------------------------------------------------------------===//
672 // Neg
673 //===----------------------------------------------------------------------===//
674
675 template <PrimType Name, class T = typename PrimConv<Name>::T>
Neg(InterpState & S,CodePtr OpPC)676 bool Neg(InterpState &S, CodePtr OpPC) {
677 const T &Value = S.Stk.pop<T>();
678 T Result;
679
680 if (!T::neg(Value, &Result)) {
681 S.Stk.push<T>(Result);
682 return true;
683 }
684
685 assert(isIntegralType(Name) &&
686 "don't expect other types to fail at constexpr negation");
687 S.Stk.push<T>(Result);
688
689 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
690 const Expr *E = S.Current->getExpr(OpPC);
691 QualType Type = E->getType();
692
693 if (S.checkingForUndefinedBehavior()) {
694 SmallString<32> Trunc;
695 NegatedValue.trunc(Result.bitWidth())
696 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
697 /*UpperCase=*/true, /*InsertSeparators=*/true);
698 auto Loc = E->getExprLoc();
699 S.report(Loc, diag::warn_integer_constant_overflow)
700 << Trunc << Type << E->getSourceRange();
701 return true;
702 }
703
704 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
705 return S.noteUndefinedBehavior();
706 }
707
708 enum class PushVal : bool {
709 No,
710 Yes,
711 };
712 enum class IncDecOp {
713 Inc,
714 Dec,
715 };
716
717 template <typename T, IncDecOp Op, PushVal DoPush>
IncDecHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr)718 bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
719 assert(!Ptr.isDummy());
720
721 if constexpr (std::is_same_v<T, Boolean>) {
722 if (!S.getLangOpts().CPlusPlus14)
723 return Invalid(S, OpPC);
724 }
725
726 const T &Value = Ptr.deref<T>();
727 T Result;
728
729 if constexpr (DoPush == PushVal::Yes)
730 S.Stk.push<T>(Value);
731
732 if constexpr (Op == IncDecOp::Inc) {
733 if (!T::increment(Value, &Result)) {
734 Ptr.deref<T>() = Result;
735 return true;
736 }
737 } else {
738 if (!T::decrement(Value, &Result)) {
739 Ptr.deref<T>() = Result;
740 return true;
741 }
742 }
743
744 // Something went wrong with the previous operation. Compute the
745 // result with another bit of precision.
746 unsigned Bits = Value.bitWidth() + 1;
747 APSInt APResult;
748 if constexpr (Op == IncDecOp::Inc)
749 APResult = ++Value.toAPSInt(Bits);
750 else
751 APResult = --Value.toAPSInt(Bits);
752
753 // Report undefined behaviour, stopping if required.
754 const Expr *E = S.Current->getExpr(OpPC);
755 QualType Type = E->getType();
756 if (S.checkingForUndefinedBehavior()) {
757 SmallString<32> Trunc;
758 APResult.trunc(Result.bitWidth())
759 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
760 /*UpperCase=*/true, /*InsertSeparators=*/true);
761 auto Loc = E->getExprLoc();
762 S.report(Loc, diag::warn_integer_constant_overflow)
763 << Trunc << Type << E->getSourceRange();
764 return true;
765 }
766
767 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
768 return S.noteUndefinedBehavior();
769 }
770
771 /// 1) Pops a pointer from the stack
772 /// 2) Load the value from the pointer
773 /// 3) Writes the value increased by one back to the pointer
774 /// 4) Pushes the original (pre-inc) value on the stack.
775 template <PrimType Name, class T = typename PrimConv<Name>::T>
Inc(InterpState & S,CodePtr OpPC)776 bool Inc(InterpState &S, CodePtr OpPC) {
777 const Pointer &Ptr = S.Stk.pop<Pointer>();
778 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
779 return false;
780
781 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
782 }
783
784 /// 1) Pops a pointer from the stack
785 /// 2) Load the value from the pointer
786 /// 3) Writes the value increased by one back to the pointer
787 template <PrimType Name, class T = typename PrimConv<Name>::T>
IncPop(InterpState & S,CodePtr OpPC)788 bool IncPop(InterpState &S, CodePtr OpPC) {
789 const Pointer &Ptr = S.Stk.pop<Pointer>();
790 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
791 return false;
792
793 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
794 }
795
796 /// 1) Pops a pointer from the stack
797 /// 2) Load the value from the pointer
798 /// 3) Writes the value decreased by one back to the pointer
799 /// 4) Pushes the original (pre-dec) value on the stack.
800 template <PrimType Name, class T = typename PrimConv<Name>::T>
Dec(InterpState & S,CodePtr OpPC)801 bool Dec(InterpState &S, CodePtr OpPC) {
802 const Pointer &Ptr = S.Stk.pop<Pointer>();
803 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
804 return false;
805
806 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
807 }
808
809 /// 1) Pops a pointer from the stack
810 /// 2) Load the value from the pointer
811 /// 3) Writes the value decreased by one back to the pointer
812 template <PrimType Name, class T = typename PrimConv<Name>::T>
DecPop(InterpState & S,CodePtr OpPC)813 bool DecPop(InterpState &S, CodePtr OpPC) {
814 const Pointer &Ptr = S.Stk.pop<Pointer>();
815 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
816 return false;
817
818 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
819 }
820
821 template <IncDecOp Op, PushVal DoPush>
IncDecFloatHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr,llvm::RoundingMode RM)822 bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
823 llvm::RoundingMode RM) {
824 Floating Value = Ptr.deref<Floating>();
825 Floating Result;
826
827 if constexpr (DoPush == PushVal::Yes)
828 S.Stk.push<Floating>(Value);
829
830 llvm::APFloat::opStatus Status;
831 if constexpr (Op == IncDecOp::Inc)
832 Status = Floating::increment(Value, RM, &Result);
833 else
834 Status = Floating::decrement(Value, RM, &Result);
835
836 Ptr.deref<Floating>() = Result;
837
838 return CheckFloatResult(S, OpPC, Result, Status);
839 }
840
Incf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)841 inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
842 const Pointer &Ptr = S.Stk.pop<Pointer>();
843 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
844 return false;
845
846 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
847 }
848
IncfPop(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)849 inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
850 const Pointer &Ptr = S.Stk.pop<Pointer>();
851 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
852 return false;
853
854 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
855 }
856
Decf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)857 inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
858 const Pointer &Ptr = S.Stk.pop<Pointer>();
859 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
860 return false;
861
862 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
863 }
864
DecfPop(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)865 inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
866 const Pointer &Ptr = S.Stk.pop<Pointer>();
867 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
868 return false;
869
870 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
871 }
872
873 /// 1) Pops the value from the stack.
874 /// 2) Pushes the bitwise complemented value on the stack (~V).
875 template <PrimType Name, class T = typename PrimConv<Name>::T>
Comp(InterpState & S,CodePtr OpPC)876 bool Comp(InterpState &S, CodePtr OpPC) {
877 const T &Val = S.Stk.pop<T>();
878 T Result;
879 if (!T::comp(Val, &Result)) {
880 S.Stk.push<T>(Result);
881 return true;
882 }
883
884 return false;
885 }
886
887 //===----------------------------------------------------------------------===//
888 // EQ, NE, GT, GE, LT, LE
889 //===----------------------------------------------------------------------===//
890
891 using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
892
893 template <typename T>
CmpHelper(InterpState & S,CodePtr OpPC,CompareFn Fn)894 bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
895 assert((!std::is_same_v<T, MemberPointer>) &&
896 "Non-equality comparisons on member pointer types should already be "
897 "rejected in Sema.");
898 using BoolT = PrimConv<PT_Bool>::T;
899 const T &RHS = S.Stk.pop<T>();
900 const T &LHS = S.Stk.pop<T>();
901 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
902 return true;
903 }
904
905 template <typename T>
CmpHelperEQ(InterpState & S,CodePtr OpPC,CompareFn Fn)906 bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
907 return CmpHelper<T>(S, OpPC, Fn);
908 }
909
910 /// Function pointers cannot be compared in an ordered way.
911 template <>
912 inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
913 CompareFn Fn) {
914 const auto &RHS = S.Stk.pop<FunctionPointer>();
915 const auto &LHS = S.Stk.pop<FunctionPointer>();
916
917 const SourceInfo &Loc = S.Current->getSource(OpPC);
918 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
919 << LHS.toDiagnosticString(S.getCtx())
920 << RHS.toDiagnosticString(S.getCtx());
921 return false;
922 }
923
924 template <>
925 inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
926 CompareFn Fn) {
927 const auto &RHS = S.Stk.pop<FunctionPointer>();
928 const auto &LHS = S.Stk.pop<FunctionPointer>();
929
930 // We cannot compare against weak declarations at compile time.
931 for (const auto &FP : {LHS, RHS}) {
932 if (FP.isWeak()) {
933 const SourceInfo &Loc = S.Current->getSource(OpPC);
934 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
935 << FP.toDiagnosticString(S.getCtx());
936 return false;
937 }
938 }
939
940 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
941 return true;
942 }
943
944 template <>
945 inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
946 using BoolT = PrimConv<PT_Bool>::T;
947 const Pointer &RHS = S.Stk.pop<Pointer>();
948 const Pointer &LHS = S.Stk.pop<Pointer>();
949
950 if (!Pointer::hasSameBase(LHS, RHS)) {
951 const SourceInfo &Loc = S.Current->getSource(OpPC);
952 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
953 << LHS.toDiagnosticString(S.getCtx())
954 << RHS.toDiagnosticString(S.getCtx());
955 return false;
956 } else {
957 unsigned VL = LHS.getByteOffset();
958 unsigned VR = RHS.getByteOffset();
959 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
960 return true;
961 }
962 }
963
964 template <>
965 inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
966 using BoolT = PrimConv<PT_Bool>::T;
967 const Pointer &RHS = S.Stk.pop<Pointer>();
968 const Pointer &LHS = S.Stk.pop<Pointer>();
969
970 if (LHS.isZero() && RHS.isZero()) {
971 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
972 return true;
973 }
974
975 // Reject comparisons to weak pointers.
976 for (const auto &P : {LHS, RHS}) {
977 if (P.isZero())
978 continue;
979 if (P.isWeak()) {
980 const SourceInfo &Loc = S.Current->getSource(OpPC);
981 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
982 << P.toDiagnosticString(S.getCtx());
983 return false;
984 }
985 }
986
987 if (!Pointer::hasSameBase(LHS, RHS)) {
988 if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
989 RHS.getOffset() == 0) {
990 const SourceInfo &Loc = S.Current->getSource(OpPC);
991 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
992 << LHS.toDiagnosticString(S.getCtx());
993 return false;
994 } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
995 LHS.getOffset() == 0) {
996 const SourceInfo &Loc = S.Current->getSource(OpPC);
997 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
998 << RHS.toDiagnosticString(S.getCtx());
999 return false;
1000 }
1001
1002 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
1003 return true;
1004 } else {
1005 unsigned VL = LHS.getByteOffset();
1006 unsigned VR = RHS.getByteOffset();
1007
1008 // In our Pointer class, a pointer to an array and a pointer to the first
1009 // element in the same array are NOT equal. They have the same Base value,
1010 // but a different Offset. This is a pretty rare case, so we fix this here
1011 // by comparing pointers to the first elements.
1012 if (!LHS.isZero() && LHS.isArrayRoot())
1013 VL = LHS.atIndex(0).getByteOffset();
1014 if (!RHS.isZero() && RHS.isArrayRoot())
1015 VR = RHS.atIndex(0).getByteOffset();
1016
1017 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1018 return true;
1019 }
1020 }
1021
1022 template <>
1023 inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
1024 CompareFn Fn) {
1025 const auto &RHS = S.Stk.pop<MemberPointer>();
1026 const auto &LHS = S.Stk.pop<MemberPointer>();
1027
1028 // If either operand is a pointer to a weak function, the comparison is not
1029 // constant.
1030 for (const auto &MP : {LHS, RHS}) {
1031 if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {
1032 const SourceInfo &Loc = S.Current->getSource(OpPC);
1033 S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;
1034 return false;
1035 }
1036 }
1037
1038 // C++11 [expr.eq]p2:
1039 // If both operands are null, they compare equal. Otherwise if only one is
1040 // null, they compare unequal.
1041 if (LHS.isZero() && RHS.isZero()) {
1042 S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));
1043 return true;
1044 }
1045 if (LHS.isZero() || RHS.isZero()) {
1046 S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));
1047 return true;
1048 }
1049
1050 // We cannot compare against virtual declarations at compile time.
1051 for (const auto &MP : {LHS, RHS}) {
1052 if (const CXXMethodDecl *MD = MP.getMemberFunction();
1053 MD && MD->isVirtual()) {
1054 const SourceInfo &Loc = S.Current->getSource(OpPC);
1055 S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1056 }
1057 }
1058
1059 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
1060 return true;
1061 }
1062
1063 template <PrimType Name, class T = typename PrimConv<Name>::T>
EQ(InterpState & S,CodePtr OpPC)1064 bool EQ(InterpState &S, CodePtr OpPC) {
1065 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1066 return R == ComparisonCategoryResult::Equal;
1067 });
1068 }
1069
1070 template <PrimType Name, class T = typename PrimConv<Name>::T>
CMP3(InterpState & S,CodePtr OpPC,const ComparisonCategoryInfo * CmpInfo)1071 bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1072 const T &RHS = S.Stk.pop<T>();
1073 const T &LHS = S.Stk.pop<T>();
1074 const Pointer &P = S.Stk.peek<Pointer>();
1075
1076 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1077 if (CmpResult == ComparisonCategoryResult::Unordered) {
1078 // This should only happen with pointers.
1079 const SourceInfo &Loc = S.Current->getSource(OpPC);
1080 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1081 << LHS.toDiagnosticString(S.getCtx())
1082 << RHS.toDiagnosticString(S.getCtx());
1083 return false;
1084 }
1085
1086 assert(CmpInfo);
1087 const auto *CmpValueInfo =
1088 CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
1089 assert(CmpValueInfo);
1090 assert(CmpValueInfo->hasValidIntValue());
1091 return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
1092 }
1093
1094 template <PrimType Name, class T = typename PrimConv<Name>::T>
NE(InterpState & S,CodePtr OpPC)1095 bool NE(InterpState &S, CodePtr OpPC) {
1096 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1097 return R != ComparisonCategoryResult::Equal;
1098 });
1099 }
1100
1101 template <PrimType Name, class T = typename PrimConv<Name>::T>
LT(InterpState & S,CodePtr OpPC)1102 bool LT(InterpState &S, CodePtr OpPC) {
1103 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1104 return R == ComparisonCategoryResult::Less;
1105 });
1106 }
1107
1108 template <PrimType Name, class T = typename PrimConv<Name>::T>
LE(InterpState & S,CodePtr OpPC)1109 bool LE(InterpState &S, CodePtr OpPC) {
1110 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1111 return R == ComparisonCategoryResult::Less ||
1112 R == ComparisonCategoryResult::Equal;
1113 });
1114 }
1115
1116 template <PrimType Name, class T = typename PrimConv<Name>::T>
GT(InterpState & S,CodePtr OpPC)1117 bool GT(InterpState &S, CodePtr OpPC) {
1118 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1119 return R == ComparisonCategoryResult::Greater;
1120 });
1121 }
1122
1123 template <PrimType Name, class T = typename PrimConv<Name>::T>
GE(InterpState & S,CodePtr OpPC)1124 bool GE(InterpState &S, CodePtr OpPC) {
1125 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1126 return R == ComparisonCategoryResult::Greater ||
1127 R == ComparisonCategoryResult::Equal;
1128 });
1129 }
1130
1131 //===----------------------------------------------------------------------===//
1132 // InRange
1133 //===----------------------------------------------------------------------===//
1134
1135 template <PrimType Name, class T = typename PrimConv<Name>::T>
InRange(InterpState & S,CodePtr OpPC)1136 bool InRange(InterpState &S, CodePtr OpPC) {
1137 const T RHS = S.Stk.pop<T>();
1138 const T LHS = S.Stk.pop<T>();
1139 const T Value = S.Stk.pop<T>();
1140
1141 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
1142 return true;
1143 }
1144
1145 //===----------------------------------------------------------------------===//
1146 // Dup, Pop, Test
1147 //===----------------------------------------------------------------------===//
1148
1149 template <PrimType Name, class T = typename PrimConv<Name>::T>
Dup(InterpState & S,CodePtr OpPC)1150 bool Dup(InterpState &S, CodePtr OpPC) {
1151 S.Stk.push<T>(S.Stk.peek<T>());
1152 return true;
1153 }
1154
1155 template <PrimType Name, class T = typename PrimConv<Name>::T>
Pop(InterpState & S,CodePtr OpPC)1156 bool Pop(InterpState &S, CodePtr OpPC) {
1157 S.Stk.pop<T>();
1158 return true;
1159 }
1160
1161 //===----------------------------------------------------------------------===//
1162 // Const
1163 //===----------------------------------------------------------------------===//
1164
1165 template <PrimType Name, class T = typename PrimConv<Name>::T>
Const(InterpState & S,CodePtr OpPC,const T & Arg)1166 bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1167 S.Stk.push<T>(Arg);
1168 return true;
1169 }
1170
1171 //===----------------------------------------------------------------------===//
1172 // Get/Set Local/Param/Global/This
1173 //===----------------------------------------------------------------------===//
1174
1175 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetLocal(InterpState & S,CodePtr OpPC,uint32_t I)1176 bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1177 const Pointer &Ptr = S.Current->getLocalPointer(I);
1178 if (!CheckLoad(S, OpPC, Ptr))
1179 return false;
1180 S.Stk.push<T>(Ptr.deref<T>());
1181 return true;
1182 }
1183
1184 /// 1) Pops the value from the stack.
1185 /// 2) Writes the value to the local variable with the
1186 /// given offset.
1187 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetLocal(InterpState & S,CodePtr OpPC,uint32_t I)1188 bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1189 S.Current->setLocal<T>(I, S.Stk.pop<T>());
1190 return true;
1191 }
1192
1193 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetParam(InterpState & S,CodePtr OpPC,uint32_t I)1194 bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1195 if (S.checkingPotentialConstantExpression()) {
1196 return false;
1197 }
1198 S.Stk.push<T>(S.Current->getParam<T>(I));
1199 return true;
1200 }
1201
1202 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetParam(InterpState & S,CodePtr OpPC,uint32_t I)1203 bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1204 S.Current->setParam<T>(I, S.Stk.pop<T>());
1205 return true;
1206 }
1207
1208 /// 1) Peeks a pointer on the stack
1209 /// 2) Pushes the value of the pointer's field on the stack
1210 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetField(InterpState & S,CodePtr OpPC,uint32_t I)1211 bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1212 const Pointer &Obj = S.Stk.peek<Pointer>();
1213 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1214 return false;
1215 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1216 return false;
1217 const Pointer &Field = Obj.atField(I);
1218 if (!CheckLoad(S, OpPC, Field))
1219 return false;
1220 S.Stk.push<T>(Field.deref<T>());
1221 return true;
1222 }
1223
1224 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetField(InterpState & S,CodePtr OpPC,uint32_t I)1225 bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1226 const T &Value = S.Stk.pop<T>();
1227 const Pointer &Obj = S.Stk.peek<Pointer>();
1228 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1229 return false;
1230 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1231 return false;
1232 const Pointer &Field = Obj.atField(I);
1233 if (!CheckStore(S, OpPC, Field))
1234 return false;
1235 Field.initialize();
1236 Field.deref<T>() = Value;
1237 return true;
1238 }
1239
1240 /// 1) Pops a pointer from the stack
1241 /// 2) Pushes the value of the pointer's field on the stack
1242 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetFieldPop(InterpState & S,CodePtr OpPC,uint32_t I)1243 bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1244 const Pointer &Obj = S.Stk.pop<Pointer>();
1245 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1246 return false;
1247 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1248 return false;
1249 const Pointer &Field = Obj.atField(I);
1250 if (!CheckLoad(S, OpPC, Field))
1251 return false;
1252 S.Stk.push<T>(Field.deref<T>());
1253 return true;
1254 }
1255
1256 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetThisField(InterpState & S,CodePtr OpPC,uint32_t I)1257 bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1258 if (S.checkingPotentialConstantExpression())
1259 return false;
1260 const Pointer &This = S.Current->getThis();
1261 if (!CheckThis(S, OpPC, This))
1262 return false;
1263 const Pointer &Field = This.atField(I);
1264 if (!CheckLoad(S, OpPC, Field))
1265 return false;
1266 S.Stk.push<T>(Field.deref<T>());
1267 return true;
1268 }
1269
1270 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetThisField(InterpState & S,CodePtr OpPC,uint32_t I)1271 bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1272 if (S.checkingPotentialConstantExpression())
1273 return false;
1274 const T &Value = S.Stk.pop<T>();
1275 const Pointer &This = S.Current->getThis();
1276 if (!CheckThis(S, OpPC, This))
1277 return false;
1278 const Pointer &Field = This.atField(I);
1279 if (!CheckStore(S, OpPC, Field))
1280 return false;
1281 Field.deref<T>() = Value;
1282 return true;
1283 }
1284
1285 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1286 bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1287 const Pointer &Ptr = S.P.getPtrGlobal(I);
1288 if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1289 return false;
1290 if (Ptr.isExtern())
1291 return false;
1292
1293 // If a global variable is uninitialized, that means the initializer we've
1294 // compiled for it wasn't a constant expression. Diagnose that.
1295 if (!CheckGlobalInitialized(S, OpPC, Ptr))
1296 return false;
1297
1298 S.Stk.push<T>(Ptr.deref<T>());
1299 return true;
1300 }
1301
1302 /// Same as GetGlobal, but without the checks.
1303 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobalUnchecked(InterpState & S,CodePtr OpPC,uint32_t I)1304 bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1305 const Pointer &Ptr = S.P.getPtrGlobal(I);
1306 if (!Ptr.isInitialized())
1307 return false;
1308 S.Stk.push<T>(Ptr.deref<T>());
1309 return true;
1310 }
1311
1312 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1313 bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1314 // TODO: emit warning.
1315 return false;
1316 }
1317
1318 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1319 bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1320 const Pointer &P = S.P.getGlobal(I);
1321 P.deref<T>() = S.Stk.pop<T>();
1322 P.initialize();
1323 return true;
1324 }
1325
1326 /// 1) Converts the value on top of the stack to an APValue
1327 /// 2) Sets that APValue on \Temp
1328 /// 3) Initializes global with index \I with that
1329 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobalTemp(InterpState & S,CodePtr OpPC,uint32_t I,const LifetimeExtendedTemporaryDecl * Temp)1330 bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1331 const LifetimeExtendedTemporaryDecl *Temp) {
1332 const Pointer &Ptr = S.P.getGlobal(I);
1333
1334 const T Value = S.Stk.peek<T>();
1335 APValue APV = Value.toAPValue(S.getCtx());
1336 APValue *Cached = Temp->getOrCreateValue(true);
1337 *Cached = APV;
1338
1339 assert(Ptr.getDeclDesc()->asExpr());
1340
1341 S.SeenGlobalTemporaries.push_back(
1342 std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
1343
1344 Ptr.deref<T>() = S.Stk.pop<T>();
1345 Ptr.initialize();
1346 return true;
1347 }
1348
1349 /// 1) Converts the value on top of the stack to an APValue
1350 /// 2) Sets that APValue on \Temp
1351 /// 3) Initialized global with index \I with that
InitGlobalTempComp(InterpState & S,CodePtr OpPC,const LifetimeExtendedTemporaryDecl * Temp)1352 inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
1353 const LifetimeExtendedTemporaryDecl *Temp) {
1354 assert(Temp);
1355 const Pointer &P = S.Stk.peek<Pointer>();
1356 APValue *Cached = Temp->getOrCreateValue(true);
1357
1358 S.SeenGlobalTemporaries.push_back(
1359 std::make_pair(P.getDeclDesc()->asExpr(), Temp));
1360
1361 if (std::optional<APValue> APV =
1362 P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
1363 *Cached = *APV;
1364 return true;
1365 }
1366
1367 return false;
1368 }
1369
1370 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisField(InterpState & S,CodePtr OpPC,uint32_t I)1371 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1372 if (S.checkingPotentialConstantExpression())
1373 return false;
1374 const Pointer &This = S.Current->getThis();
1375 if (!CheckThis(S, OpPC, This))
1376 return false;
1377 const Pointer &Field = This.atField(I);
1378 Field.deref<T>() = S.Stk.pop<T>();
1379 Field.initialize();
1380 return true;
1381 }
1382
1383 // FIXME: The Field pointer here is too much IMO and we could instead just
1384 // pass an Offset + BitWidth pair.
1385 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisBitField(InterpState & S,CodePtr OpPC,const Record::Field * F,uint32_t FieldOffset)1386 bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1387 uint32_t FieldOffset) {
1388 assert(F->isBitField());
1389 if (S.checkingPotentialConstantExpression())
1390 return false;
1391 const Pointer &This = S.Current->getThis();
1392 if (!CheckThis(S, OpPC, This))
1393 return false;
1394 const Pointer &Field = This.atField(FieldOffset);
1395 const auto &Value = S.Stk.pop<T>();
1396 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1397 Field.initialize();
1398 return true;
1399 }
1400
1401 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)1402 bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1403 if (S.checkingPotentialConstantExpression())
1404 return false;
1405 const Pointer &This = S.Current->getThis();
1406 if (!CheckThis(S, OpPC, This))
1407 return false;
1408 const Pointer &Field = This.atField(I);
1409 Field.deref<T>() = S.Stk.pop<T>();
1410 Field.activate();
1411 Field.initialize();
1412 return true;
1413 }
1414
1415 /// 1) Pops the value from the stack
1416 /// 2) Peeks a pointer from the stack
1417 /// 3) Pushes the value to field I of the pointer on the stack
1418 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitField(InterpState & S,CodePtr OpPC,uint32_t I)1419 bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1420 const T &Value = S.Stk.pop<T>();
1421 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1422 Field.deref<T>() = Value;
1423 Field.activate();
1424 Field.initialize();
1425 return true;
1426 }
1427
1428 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)1429 bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1430 assert(F->isBitField());
1431 const T &Value = S.Stk.pop<T>();
1432 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1433 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1434 Field.activate();
1435 Field.initialize();
1436 return true;
1437 }
1438
1439 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)1440 bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1441 const T &Value = S.Stk.pop<T>();
1442 const Pointer &Ptr = S.Stk.pop<Pointer>();
1443 const Pointer &Field = Ptr.atField(I);
1444 Field.deref<T>() = Value;
1445 Field.activate();
1446 Field.initialize();
1447 return true;
1448 }
1449
1450 //===----------------------------------------------------------------------===//
1451 // GetPtr Local/Param/Global/Field/This
1452 //===----------------------------------------------------------------------===//
1453
GetPtrLocal(InterpState & S,CodePtr OpPC,uint32_t I)1454 inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1455 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1456 return true;
1457 }
1458
GetPtrParam(InterpState & S,CodePtr OpPC,uint32_t I)1459 inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1460 if (S.checkingPotentialConstantExpression()) {
1461 return false;
1462 }
1463 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1464 return true;
1465 }
1466
GetPtrGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1467 inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1468 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1469 return true;
1470 }
1471
1472 /// 1) Peeks a Pointer
1473 /// 2) Pushes Pointer.atField(Off) on the stack
GetPtrField(InterpState & S,CodePtr OpPC,uint32_t Off)1474 inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1475 const Pointer &Ptr = S.Stk.peek<Pointer>();
1476
1477 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1478 !CheckNull(S, OpPC, Ptr, CSK_Field))
1479 return false;
1480
1481 if (!CheckExtern(S, OpPC, Ptr))
1482 return false;
1483 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1484 return false;
1485 if (!CheckArray(S, OpPC, Ptr))
1486 return false;
1487 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1488 return false;
1489
1490 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1491 return false;
1492 S.Stk.push<Pointer>(Ptr.atField(Off));
1493 return true;
1494 }
1495
GetPtrFieldPop(InterpState & S,CodePtr OpPC,uint32_t Off)1496 inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1497 const Pointer &Ptr = S.Stk.pop<Pointer>();
1498
1499 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1500 !CheckNull(S, OpPC, Ptr, CSK_Field))
1501 return false;
1502
1503 if (!CheckExtern(S, OpPC, Ptr))
1504 return false;
1505 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1506 return false;
1507 if (!CheckArray(S, OpPC, Ptr))
1508 return false;
1509 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1510 return false;
1511
1512 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1513 return false;
1514
1515 S.Stk.push<Pointer>(Ptr.atField(Off));
1516 return true;
1517 }
1518
GetPtrThisField(InterpState & S,CodePtr OpPC,uint32_t Off)1519 inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1520 if (S.checkingPotentialConstantExpression())
1521 return false;
1522 const Pointer &This = S.Current->getThis();
1523 if (!CheckThis(S, OpPC, This))
1524 return false;
1525 S.Stk.push<Pointer>(This.atField(Off));
1526 return true;
1527 }
1528
GetPtrActiveField(InterpState & S,CodePtr OpPC,uint32_t Off)1529 inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1530 const Pointer &Ptr = S.Stk.pop<Pointer>();
1531 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1532 return false;
1533 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1534 return false;
1535 Pointer Field = Ptr.atField(Off);
1536 Ptr.deactivate();
1537 Field.activate();
1538 S.Stk.push<Pointer>(std::move(Field));
1539 return true;
1540 }
1541
GetPtrActiveThisField(InterpState & S,CodePtr OpPC,uint32_t Off)1542 inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1543 if (S.checkingPotentialConstantExpression())
1544 return false;
1545 const Pointer &This = S.Current->getThis();
1546 if (!CheckThis(S, OpPC, This))
1547 return false;
1548 Pointer Field = This.atField(Off);
1549 This.deactivate();
1550 Field.activate();
1551 S.Stk.push<Pointer>(std::move(Field));
1552 return true;
1553 }
1554
GetPtrDerivedPop(InterpState & S,CodePtr OpPC,uint32_t Off)1555 inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1556 const Pointer &Ptr = S.Stk.pop<Pointer>();
1557 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1558 return false;
1559 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1560 return false;
1561 if (!CheckDowncast(S, OpPC, Ptr, Off))
1562 return false;
1563
1564 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1565 return true;
1566 }
1567
GetPtrBase(InterpState & S,CodePtr OpPC,uint32_t Off)1568 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1569 const Pointer &Ptr = S.Stk.peek<Pointer>();
1570 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1571 return false;
1572 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1573 return false;
1574 S.Stk.push<Pointer>(Ptr.atField(Off));
1575 return true;
1576 }
1577
GetPtrBasePop(InterpState & S,CodePtr OpPC,uint32_t Off)1578 inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1579 const Pointer &Ptr = S.Stk.pop<Pointer>();
1580 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1581 return false;
1582 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1583 return false;
1584 S.Stk.push<Pointer>(Ptr.atField(Off));
1585 return true;
1586 }
1587
GetMemberPtrBasePop(InterpState & S,CodePtr OpPC,int32_t Off)1588 inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
1589 const auto &Ptr = S.Stk.pop<MemberPointer>();
1590 S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
1591 return true;
1592 }
1593
GetPtrThisBase(InterpState & S,CodePtr OpPC,uint32_t Off)1594 inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1595 if (S.checkingPotentialConstantExpression())
1596 return false;
1597 const Pointer &This = S.Current->getThis();
1598 if (!CheckThis(S, OpPC, This))
1599 return false;
1600 S.Stk.push<Pointer>(This.atField(Off));
1601 return true;
1602 }
1603
FinishInitPop(InterpState & S,CodePtr OpPC)1604 inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1605 const Pointer &Ptr = S.Stk.pop<Pointer>();
1606 if (Ptr.canBeInitialized()) {
1607 Ptr.initialize();
1608 Ptr.activate();
1609 }
1610 return true;
1611 }
1612
FinishInit(InterpState & S,CodePtr OpPC)1613 inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1614 const Pointer &Ptr = S.Stk.peek<Pointer>();
1615 if (Ptr.canBeInitialized()) {
1616 Ptr.initialize();
1617 Ptr.activate();
1618 }
1619 return true;
1620 }
1621
Dump(InterpState & S,CodePtr OpPC)1622 inline bool Dump(InterpState &S, CodePtr OpPC) {
1623 S.Stk.dump();
1624 return true;
1625 }
1626
VirtBaseHelper(InterpState & S,CodePtr OpPC,const RecordDecl * Decl,const Pointer & Ptr)1627 inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1628 const Pointer &Ptr) {
1629 Pointer Base = Ptr;
1630 while (Base.isBaseClass())
1631 Base = Base.getBase();
1632
1633 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1634 S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1635 return true;
1636 }
1637
GetPtrVirtBasePop(InterpState & S,CodePtr OpPC,const RecordDecl * D)1638 inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
1639 const RecordDecl *D) {
1640 assert(D);
1641 const Pointer &Ptr = S.Stk.pop<Pointer>();
1642 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1643 return false;
1644 return VirtBaseHelper(S, OpPC, D, Ptr);
1645 }
1646
GetPtrThisVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)1647 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1648 const RecordDecl *D) {
1649 assert(D);
1650 if (S.checkingPotentialConstantExpression())
1651 return false;
1652 const Pointer &This = S.Current->getThis();
1653 if (!CheckThis(S, OpPC, This))
1654 return false;
1655 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1656 }
1657
1658 //===----------------------------------------------------------------------===//
1659 // Load, Store, Init
1660 //===----------------------------------------------------------------------===//
1661
1662 template <PrimType Name, class T = typename PrimConv<Name>::T>
Load(InterpState & S,CodePtr OpPC)1663 bool Load(InterpState &S, CodePtr OpPC) {
1664 const Pointer &Ptr = S.Stk.peek<Pointer>();
1665 if (!CheckLoad(S, OpPC, Ptr))
1666 return false;
1667 if (!Ptr.isBlockPointer())
1668 return false;
1669 S.Stk.push<T>(Ptr.deref<T>());
1670 return true;
1671 }
1672
1673 template <PrimType Name, class T = typename PrimConv<Name>::T>
LoadPop(InterpState & S,CodePtr OpPC)1674 bool LoadPop(InterpState &S, CodePtr OpPC) {
1675 const Pointer &Ptr = S.Stk.pop<Pointer>();
1676 if (!CheckLoad(S, OpPC, Ptr))
1677 return false;
1678 if (!Ptr.isBlockPointer())
1679 return false;
1680 S.Stk.push<T>(Ptr.deref<T>());
1681 return true;
1682 }
1683
1684 template <PrimType Name, class T = typename PrimConv<Name>::T>
Store(InterpState & S,CodePtr OpPC)1685 bool Store(InterpState &S, CodePtr OpPC) {
1686 const T &Value = S.Stk.pop<T>();
1687 const Pointer &Ptr = S.Stk.peek<Pointer>();
1688 if (!CheckStore(S, OpPC, Ptr))
1689 return false;
1690 if (Ptr.canBeInitialized())
1691 Ptr.initialize();
1692 Ptr.deref<T>() = Value;
1693 return true;
1694 }
1695
1696 template <PrimType Name, class T = typename PrimConv<Name>::T>
StorePop(InterpState & S,CodePtr OpPC)1697 bool StorePop(InterpState &S, CodePtr OpPC) {
1698 const T &Value = S.Stk.pop<T>();
1699 const Pointer &Ptr = S.Stk.pop<Pointer>();
1700 if (!CheckStore(S, OpPC, Ptr))
1701 return false;
1702 if (Ptr.canBeInitialized())
1703 Ptr.initialize();
1704 Ptr.deref<T>() = Value;
1705 return true;
1706 }
1707
1708 template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitField(InterpState & S,CodePtr OpPC)1709 bool StoreBitField(InterpState &S, CodePtr OpPC) {
1710 const T &Value = S.Stk.pop<T>();
1711 const Pointer &Ptr = S.Stk.peek<Pointer>();
1712 if (!CheckStore(S, OpPC, Ptr))
1713 return false;
1714 if (Ptr.canBeInitialized())
1715 Ptr.initialize();
1716 if (const auto *FD = Ptr.getField())
1717 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1718 else
1719 Ptr.deref<T>() = Value;
1720 return true;
1721 }
1722
1723 template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitFieldPop(InterpState & S,CodePtr OpPC)1724 bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1725 const T &Value = S.Stk.pop<T>();
1726 const Pointer &Ptr = S.Stk.pop<Pointer>();
1727 if (!CheckStore(S, OpPC, Ptr))
1728 return false;
1729 if (Ptr.canBeInitialized())
1730 Ptr.initialize();
1731 if (const auto *FD = Ptr.getField())
1732 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1733 else
1734 Ptr.deref<T>() = Value;
1735 return true;
1736 }
1737
1738 template <PrimType Name, class T = typename PrimConv<Name>::T>
Init(InterpState & S,CodePtr OpPC)1739 bool Init(InterpState &S, CodePtr OpPC) {
1740 const T &Value = S.Stk.pop<T>();
1741 const Pointer &Ptr = S.Stk.peek<Pointer>();
1742 if (!CheckInit(S, OpPC, Ptr)) {
1743 assert(false);
1744 return false;
1745 }
1746 Ptr.initialize();
1747 new (&Ptr.deref<T>()) T(Value);
1748 return true;
1749 }
1750
1751 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitPop(InterpState & S,CodePtr OpPC)1752 bool InitPop(InterpState &S, CodePtr OpPC) {
1753 const T &Value = S.Stk.pop<T>();
1754 const Pointer &Ptr = S.Stk.pop<Pointer>();
1755 if (!CheckInit(S, OpPC, Ptr))
1756 return false;
1757 Ptr.initialize();
1758 new (&Ptr.deref<T>()) T(Value);
1759 return true;
1760 }
1761
1762 /// 1) Pops the value from the stack
1763 /// 2) Peeks a pointer and gets its index \Idx
1764 /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1765 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElem(InterpState & S,CodePtr OpPC,uint32_t Idx)1766 bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1767 const T &Value = S.Stk.pop<T>();
1768 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1769 if (Ptr.isUnknownSizeArray())
1770 return false;
1771 if (!CheckInit(S, OpPC, Ptr))
1772 return false;
1773 Ptr.initialize();
1774 new (&Ptr.deref<T>()) T(Value);
1775 return true;
1776 }
1777
1778 /// The same as InitElem, but pops the pointer as well.
1779 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElemPop(InterpState & S,CodePtr OpPC,uint32_t Idx)1780 bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1781 const T &Value = S.Stk.pop<T>();
1782 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1783 if (Ptr.isUnknownSizeArray())
1784 return false;
1785 if (!CheckInit(S, OpPC, Ptr))
1786 return false;
1787 Ptr.initialize();
1788 new (&Ptr.deref<T>()) T(Value);
1789 return true;
1790 }
1791
Memcpy(InterpState & S,CodePtr OpPC)1792 inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1793 const Pointer &Src = S.Stk.pop<Pointer>();
1794 Pointer &Dest = S.Stk.peek<Pointer>();
1795
1796 if (!CheckLoad(S, OpPC, Src))
1797 return false;
1798
1799 return DoMemcpy(S, OpPC, Src, Dest);
1800 }
1801
ToMemberPtr(InterpState & S,CodePtr OpPC)1802 inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
1803 const auto &Member = S.Stk.pop<MemberPointer>();
1804 const auto &Base = S.Stk.pop<Pointer>();
1805
1806 S.Stk.push<MemberPointer>(Member.takeInstance(Base));
1807 return true;
1808 }
1809
CastMemberPtrPtr(InterpState & S,CodePtr OpPC)1810 inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
1811 const auto &MP = S.Stk.pop<MemberPointer>();
1812
1813 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
1814 S.Stk.push<Pointer>(*Ptr);
1815 return true;
1816 }
1817 return false;
1818 }
1819
1820 //===----------------------------------------------------------------------===//
1821 // AddOffset, SubOffset
1822 //===----------------------------------------------------------------------===//
1823
1824 template <class T, ArithOp Op>
OffsetHelper(InterpState & S,CodePtr OpPC,const T & Offset,const Pointer & Ptr)1825 bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1826 const Pointer &Ptr) {
1827 // A zero offset does not change the pointer.
1828 if (Offset.isZero()) {
1829 S.Stk.push<Pointer>(Ptr);
1830 return true;
1831 }
1832
1833 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
1834 // The CheckNull will have emitted a note already, but we only
1835 // abort in C++, since this is fine in C.
1836 if (S.getLangOpts().CPlusPlus)
1837 return false;
1838 }
1839
1840 // Arrays of unknown bounds cannot have pointers into them.
1841 if (!CheckArray(S, OpPC, Ptr))
1842 return false;
1843
1844 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1845 uint64_t Index;
1846 if (Ptr.isOnePastEnd())
1847 Index = MaxIndex;
1848 else
1849 Index = Ptr.getIndex();
1850
1851 bool Invalid = false;
1852 // Helper to report an invalid offset, computed as APSInt.
1853 auto DiagInvalidOffset = [&]() -> void {
1854 const unsigned Bits = Offset.bitWidth();
1855 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1856 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1857 /*IsUnsigned=*/false);
1858 APSInt NewIndex =
1859 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1860 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1861 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
1862 Invalid = true;
1863 };
1864
1865 if (Ptr.isBlockPointer()) {
1866 uint64_t IOffset = static_cast<uint64_t>(Offset);
1867 uint64_t MaxOffset = MaxIndex - Index;
1868
1869 if constexpr (Op == ArithOp::Add) {
1870 // If the new offset would be negative, bail out.
1871 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1872 DiagInvalidOffset();
1873
1874 // If the new offset would be out of bounds, bail out.
1875 if (Offset.isPositive() && IOffset > MaxOffset)
1876 DiagInvalidOffset();
1877 } else {
1878 // If the new offset would be negative, bail out.
1879 if (Offset.isPositive() && Index < IOffset)
1880 DiagInvalidOffset();
1881
1882 // If the new offset would be out of bounds, bail out.
1883 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1884 DiagInvalidOffset();
1885 }
1886 }
1887
1888 if (Invalid && S.getLangOpts().CPlusPlus)
1889 return false;
1890
1891 // Offset is valid - compute it on unsigned.
1892 int64_t WideIndex = static_cast<int64_t>(Index);
1893 int64_t WideOffset = static_cast<int64_t>(Offset);
1894 int64_t Result;
1895 if constexpr (Op == ArithOp::Add)
1896 Result = WideIndex + WideOffset;
1897 else
1898 Result = WideIndex - WideOffset;
1899
1900 // When the pointer is one-past-end, going back to index 0 is the only
1901 // useful thing we can do. Any other index has been diagnosed before and
1902 // we don't get here.
1903 if (Result == 0 && Ptr.isOnePastEnd()) {
1904 S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,
1905 Ptr.asBlockPointer().Base);
1906 return true;
1907 }
1908
1909 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
1910 return true;
1911 }
1912
1913 template <PrimType Name, class T = typename PrimConv<Name>::T>
AddOffset(InterpState & S,CodePtr OpPC)1914 bool AddOffset(InterpState &S, CodePtr OpPC) {
1915 const T &Offset = S.Stk.pop<T>();
1916 const Pointer &Ptr = S.Stk.pop<Pointer>();
1917 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1918 }
1919
1920 template <PrimType Name, class T = typename PrimConv<Name>::T>
SubOffset(InterpState & S,CodePtr OpPC)1921 bool SubOffset(InterpState &S, CodePtr OpPC) {
1922 const T &Offset = S.Stk.pop<T>();
1923 const Pointer &Ptr = S.Stk.pop<Pointer>();
1924 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1925 }
1926
1927 template <ArithOp Op>
IncDecPtrHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr)1928 static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1929 const Pointer &Ptr) {
1930 if (Ptr.isDummy())
1931 return false;
1932
1933 using OneT = Integral<8, false>;
1934
1935 const Pointer &P = Ptr.deref<Pointer>();
1936 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
1937 return false;
1938
1939 // Get the current value on the stack.
1940 S.Stk.push<Pointer>(P);
1941
1942 // Now the current Ptr again and a constant 1.
1943 OneT One = OneT::from(1);
1944 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1945 return false;
1946
1947 // Store the new value.
1948 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1949 return true;
1950 }
1951
IncPtr(InterpState & S,CodePtr OpPC)1952 static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1953 const Pointer &Ptr = S.Stk.pop<Pointer>();
1954
1955 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1956 return false;
1957
1958 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1959 }
1960
DecPtr(InterpState & S,CodePtr OpPC)1961 static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1962 const Pointer &Ptr = S.Stk.pop<Pointer>();
1963
1964 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1965 return false;
1966
1967 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1968 }
1969
1970 /// 1) Pops a Pointer from the stack.
1971 /// 2) Pops another Pointer from the stack.
1972 /// 3) Pushes the different of the indices of the two pointers on the stack.
1973 template <PrimType Name, class T = typename PrimConv<Name>::T>
SubPtr(InterpState & S,CodePtr OpPC)1974 inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1975 const Pointer &LHS = S.Stk.pop<Pointer>();
1976 const Pointer &RHS = S.Stk.pop<Pointer>();
1977
1978 if (RHS.isZero()) {
1979 S.Stk.push<T>(T::from(LHS.getIndex()));
1980 return true;
1981 }
1982
1983 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
1984 // TODO: Diagnose.
1985 return false;
1986 }
1987
1988 if (LHS.isZero() && RHS.isZero()) {
1989 S.Stk.push<T>();
1990 return true;
1991 }
1992
1993 T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
1994 : T::from(LHS.getIndex());
1995 T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
1996 : T::from(RHS.getIndex());
1997 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1998 }
1999
2000 //===----------------------------------------------------------------------===//
2001 // Destroy
2002 //===----------------------------------------------------------------------===//
2003
Destroy(InterpState & S,CodePtr OpPC,uint32_t I)2004 inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2005 S.Current->destroy(I);
2006 return true;
2007 }
2008
2009 //===----------------------------------------------------------------------===//
2010 // Cast, CastFP
2011 //===----------------------------------------------------------------------===//
2012
Cast(InterpState & S,CodePtr OpPC)2013 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2014 using T = typename PrimConv<TIn>::T;
2015 using U = typename PrimConv<TOut>::T;
2016 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2017 return true;
2018 }
2019
2020 /// 1) Pops a Floating from the stack.
2021 /// 2) Pushes a new floating on the stack that uses the given semantics.
CastFP(InterpState & S,CodePtr OpPC,const llvm::fltSemantics * Sem,llvm::RoundingMode RM)2022 inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2023 llvm::RoundingMode RM) {
2024 Floating F = S.Stk.pop<Floating>();
2025 Floating Result = F.toSemantics(Sem, RM);
2026 S.Stk.push<Floating>(Result);
2027 return true;
2028 }
2029
2030 /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2031 /// to know what bitwidth the result should be.
2032 template <PrimType Name, class T = typename PrimConv<Name>::T>
CastAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2033 bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2034 S.Stk.push<IntegralAP<false>>(
2035 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
2036 return true;
2037 }
2038
2039 template <PrimType Name, class T = typename PrimConv<Name>::T>
CastAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2040 bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2041 S.Stk.push<IntegralAP<true>>(
2042 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
2043 return true;
2044 }
2045
2046 template <PrimType Name, class T = typename PrimConv<Name>::T>
CastIntegralFloating(InterpState & S,CodePtr OpPC,const llvm::fltSemantics * Sem,llvm::RoundingMode RM)2047 bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
2048 const llvm::fltSemantics *Sem,
2049 llvm::RoundingMode RM) {
2050 const T &From = S.Stk.pop<T>();
2051 APSInt FromAP = From.toAPSInt();
2052 Floating Result;
2053
2054 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
2055 S.Stk.push<Floating>(Result);
2056
2057 return CheckFloatResult(S, OpPC, Result, Status);
2058 }
2059
2060 template <PrimType Name, class T = typename PrimConv<Name>::T>
CastFloatingIntegral(InterpState & S,CodePtr OpPC)2061 bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
2062 const Floating &F = S.Stk.pop<Floating>();
2063
2064 if constexpr (std::is_same_v<T, Boolean>) {
2065 S.Stk.push<T>(T(F.isNonZero()));
2066 return true;
2067 } else {
2068 APSInt Result(std::max(8u, T::bitWidth()),
2069 /*IsUnsigned=*/!T::isSigned());
2070 auto Status = F.convertToInteger(Result);
2071
2072 // Float-to-Integral overflow check.
2073 if ((Status & APFloat::opStatus::opInvalidOp)) {
2074 const Expr *E = S.Current->getExpr(OpPC);
2075 QualType Type = E->getType();
2076
2077 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2078 if (S.noteUndefinedBehavior()) {
2079 S.Stk.push<T>(T(Result));
2080 return true;
2081 }
2082 return false;
2083 }
2084
2085 S.Stk.push<T>(T(Result));
2086 return CheckFloatResult(S, OpPC, F, Status);
2087 }
2088 }
2089
CastFloatingIntegralAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2090 static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2091 uint32_t BitWidth) {
2092 const Floating &F = S.Stk.pop<Floating>();
2093
2094 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2095 auto Status = F.convertToInteger(Result);
2096
2097 // Float-to-Integral overflow check.
2098 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2099 const Expr *E = S.Current->getExpr(OpPC);
2100 QualType Type = E->getType();
2101
2102 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2103 return S.noteUndefinedBehavior();
2104 }
2105
2106 S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
2107 return CheckFloatResult(S, OpPC, F, Status);
2108 }
2109
CastFloatingIntegralAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2110 static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2111 uint32_t BitWidth) {
2112 const Floating &F = S.Stk.pop<Floating>();
2113
2114 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2115 auto Status = F.convertToInteger(Result);
2116
2117 // Float-to-Integral overflow check.
2118 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2119 const Expr *E = S.Current->getExpr(OpPC);
2120 QualType Type = E->getType();
2121
2122 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2123 return S.noteUndefinedBehavior();
2124 }
2125
2126 S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
2127 return CheckFloatResult(S, OpPC, F, Status);
2128 }
2129
2130 template <PrimType Name, class T = typename PrimConv<Name>::T>
CastPointerIntegral(InterpState & S,CodePtr OpPC)2131 bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
2132 const Pointer &Ptr = S.Stk.pop<Pointer>();
2133
2134 if (Ptr.isDummy())
2135 return false;
2136
2137 const SourceInfo &E = S.Current->getSource(OpPC);
2138 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2139 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2140
2141 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2142 return true;
2143 }
2144
CastPointerIntegralAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2145 static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
2146 uint32_t BitWidth) {
2147 const Pointer &Ptr = S.Stk.pop<Pointer>();
2148
2149 if (Ptr.isDummy())
2150 return false;
2151
2152 const SourceInfo &E = S.Current->getSource(OpPC);
2153 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2154 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2155
2156 S.Stk.push<IntegralAP<false>>(
2157 IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth));
2158 return true;
2159 }
2160
CastPointerIntegralAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2161 static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
2162 uint32_t BitWidth) {
2163 const Pointer &Ptr = S.Stk.pop<Pointer>();
2164
2165 if (Ptr.isDummy())
2166 return false;
2167
2168 const SourceInfo &E = S.Current->getSource(OpPC);
2169 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2170 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2171
2172 S.Stk.push<IntegralAP<true>>(
2173 IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth));
2174 return true;
2175 }
2176
PtrPtrCast(InterpState & S,CodePtr OpPC,bool SrcIsVoidPtr)2177 static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2178 const auto &Ptr = S.Stk.peek<Pointer>();
2179
2180 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2181 bool HasValidResult = !Ptr.isZero();
2182
2183 if (HasValidResult) {
2184 // FIXME: note_constexpr_invalid_void_star_cast
2185 } else if (!S.getLangOpts().CPlusPlus26) {
2186 const SourceInfo &E = S.Current->getSource(OpPC);
2187 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2188 << 3 << "'void *'" << S.Current->getRange(OpPC);
2189 }
2190 } else {
2191 const SourceInfo &E = S.Current->getSource(OpPC);
2192 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2193 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2194 }
2195
2196 return true;
2197 }
2198
2199 //===----------------------------------------------------------------------===//
2200 // Zero, Nullptr
2201 //===----------------------------------------------------------------------===//
2202
2203 template <PrimType Name, class T = typename PrimConv<Name>::T>
Zero(InterpState & S,CodePtr OpPC)2204 bool Zero(InterpState &S, CodePtr OpPC) {
2205 S.Stk.push<T>(T::zero());
2206 return true;
2207 }
2208
ZeroIntAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2209 static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2210 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
2211 return true;
2212 }
2213
ZeroIntAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2214 static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2215 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
2216 return true;
2217 }
2218
2219 template <PrimType Name, class T = typename PrimConv<Name>::T>
Null(InterpState & S,CodePtr OpPC,const Descriptor * Desc)2220 inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2221 // Note: Desc can be null.
2222 S.Stk.push<T>(0, Desc);
2223 return true;
2224 }
2225
2226 //===----------------------------------------------------------------------===//
2227 // This, ImplicitThis
2228 //===----------------------------------------------------------------------===//
2229
This(InterpState & S,CodePtr OpPC)2230 inline bool This(InterpState &S, CodePtr OpPC) {
2231 // Cannot read 'this' in this mode.
2232 if (S.checkingPotentialConstantExpression()) {
2233 return false;
2234 }
2235
2236 const Pointer &This = S.Current->getThis();
2237 if (!CheckThis(S, OpPC, This))
2238 return false;
2239
2240 // Ensure the This pointer has been cast to the correct base.
2241 if (!This.isDummy()) {
2242 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2243 assert(This.getRecord());
2244 assert(
2245 This.getRecord()->getDecl() ==
2246 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2247 }
2248
2249 S.Stk.push<Pointer>(This);
2250 return true;
2251 }
2252
RVOPtr(InterpState & S,CodePtr OpPC)2253 inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2254 assert(S.Current->getFunction()->hasRVO());
2255 if (S.checkingPotentialConstantExpression())
2256 return false;
2257 S.Stk.push<Pointer>(S.Current->getRVOPtr());
2258 return true;
2259 }
2260
2261 //===----------------------------------------------------------------------===//
2262 // Shr, Shl
2263 //===----------------------------------------------------------------------===//
2264 enum class ShiftDir { Left, Right };
2265
2266 template <class LT, class RT, ShiftDir Dir>
DoShift(InterpState & S,CodePtr OpPC,LT & LHS,RT & RHS)2267 inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2268 const unsigned Bits = LHS.bitWidth();
2269
2270 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2271 if (S.getLangOpts().OpenCL)
2272 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2273 RHS.bitWidth(), &RHS);
2274
2275 if (RHS.isNegative()) {
2276 // During constant-folding, a negative shift is an opposite shift. Such a
2277 // shift is not a constant expression.
2278 const SourceInfo &Loc = S.Current->getSource(OpPC);
2279 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2280 if (!S.noteUndefinedBehavior())
2281 return false;
2282 RHS = -RHS;
2283 return DoShift < LT, RT,
2284 Dir == ShiftDir::Left ? ShiftDir::Right
2285 : ShiftDir::Left > (S, OpPC, LHS, RHS);
2286 }
2287
2288 if constexpr (Dir == ShiftDir::Left) {
2289 if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) {
2290 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
2291 // operand, and must not overflow the corresponding unsigned type.
2292 // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
2293 // E1 x 2^E2 module 2^N.
2294 const SourceInfo &Loc = S.Current->getSource(OpPC);
2295 S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
2296 if (!S.noteUndefinedBehavior())
2297 return false;
2298 }
2299 }
2300
2301 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
2302 return false;
2303
2304 // Limit the shift amount to Bits - 1. If this happened,
2305 // it has already been diagnosed by CheckShift() above,
2306 // but we still need to handle it.
2307 typename LT::AsUnsigned R;
2308 if constexpr (Dir == ShiftDir::Left) {
2309 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2310 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2311 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2312 else
2313 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2314 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2315 } else {
2316 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2317 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2318 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2319 else
2320 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2321 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2322 }
2323
2324 S.Stk.push<LT>(LT::from(R));
2325 return true;
2326 }
2327
2328 template <PrimType NameL, PrimType NameR>
Shr(InterpState & S,CodePtr OpPC)2329 inline bool Shr(InterpState &S, CodePtr OpPC) {
2330 using LT = typename PrimConv<NameL>::T;
2331 using RT = typename PrimConv<NameR>::T;
2332 auto RHS = S.Stk.pop<RT>();
2333 auto LHS = S.Stk.pop<LT>();
2334
2335 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2336 }
2337
2338 template <PrimType NameL, PrimType NameR>
Shl(InterpState & S,CodePtr OpPC)2339 inline bool Shl(InterpState &S, CodePtr OpPC) {
2340 using LT = typename PrimConv<NameL>::T;
2341 using RT = typename PrimConv<NameR>::T;
2342 auto RHS = S.Stk.pop<RT>();
2343 auto LHS = S.Stk.pop<LT>();
2344
2345 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2346 }
2347
2348 //===----------------------------------------------------------------------===//
2349 // NoRet
2350 //===----------------------------------------------------------------------===//
2351
NoRet(InterpState & S,CodePtr OpPC)2352 inline bool NoRet(InterpState &S, CodePtr OpPC) {
2353 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2354 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2355 return false;
2356 }
2357
2358 //===----------------------------------------------------------------------===//
2359 // NarrowPtr, ExpandPtr
2360 //===----------------------------------------------------------------------===//
2361
NarrowPtr(InterpState & S,CodePtr OpPC)2362 inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2363 const Pointer &Ptr = S.Stk.pop<Pointer>();
2364 S.Stk.push<Pointer>(Ptr.narrow());
2365 return true;
2366 }
2367
ExpandPtr(InterpState & S,CodePtr OpPC)2368 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2369 const Pointer &Ptr = S.Stk.pop<Pointer>();
2370 S.Stk.push<Pointer>(Ptr.expand());
2371 return true;
2372 }
2373
2374 // 1) Pops an integral value from the stack
2375 // 2) Peeks a pointer
2376 // 3) Pushes a new pointer that's a narrowed array
2377 // element of the peeked pointer with the value
2378 // from 1) added as offset.
2379 //
2380 // This leaves the original pointer on the stack and pushes a new one
2381 // with the offset applied and narrowed.
2382 template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElemPtr(InterpState & S,CodePtr OpPC)2383 inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2384 const T &Offset = S.Stk.pop<T>();
2385 const Pointer &Ptr = S.Stk.peek<Pointer>();
2386
2387 if (!Ptr.isZero()) {
2388 if (!CheckArray(S, OpPC, Ptr))
2389 return false;
2390 }
2391
2392 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2393 return false;
2394
2395 return NarrowPtr(S, OpPC);
2396 }
2397
2398 template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElemPtrPop(InterpState & S,CodePtr OpPC)2399 inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2400 const T &Offset = S.Stk.pop<T>();
2401 const Pointer &Ptr = S.Stk.pop<Pointer>();
2402
2403 if (!Ptr.isZero()) {
2404 if (!CheckArray(S, OpPC, Ptr))
2405 return false;
2406 }
2407
2408 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2409 return false;
2410
2411 return NarrowPtr(S, OpPC);
2412 }
2413
2414 template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElem(InterpState & S,CodePtr OpPC,uint32_t Index)2415 inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2416 const Pointer &Ptr = S.Stk.peek<Pointer>();
2417
2418 if (!CheckLoad(S, OpPC, Ptr))
2419 return false;
2420
2421 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2422 return true;
2423 }
2424
2425 template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElemPop(InterpState & S,CodePtr OpPC,uint32_t Index)2426 inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2427 const Pointer &Ptr = S.Stk.pop<Pointer>();
2428
2429 if (!CheckLoad(S, OpPC, Ptr))
2430 return false;
2431
2432 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2433 return true;
2434 }
2435
2436 template <PrimType Name, class T = typename PrimConv<Name>::T>
CopyArray(InterpState & S,CodePtr OpPC,uint32_t SrcIndex,uint32_t DestIndex,uint32_t Size)2437 inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size) {
2438 const auto &SrcPtr = S.Stk.pop<Pointer>();
2439 const auto &DestPtr = S.Stk.peek<Pointer>();
2440
2441 for (uint32_t I = 0; I != Size; ++I) {
2442 const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
2443
2444 if (!CheckLoad(S, OpPC, SP))
2445 return false;
2446
2447 const Pointer &DP = DestPtr.atIndex(DestIndex + I);
2448 DP.deref<T>() = SP.deref<T>();
2449 DP.initialize();
2450 }
2451 return true;
2452 }
2453
2454 /// Just takes a pointer and checks if it's an incomplete
2455 /// array type.
ArrayDecay(InterpState & S,CodePtr OpPC)2456 inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2457 const Pointer &Ptr = S.Stk.pop<Pointer>();
2458
2459 if (Ptr.isZero()) {
2460 S.Stk.push<Pointer>(Ptr);
2461 return true;
2462 }
2463
2464 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
2465 return false;
2466
2467 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
2468 S.Stk.push<Pointer>(Ptr.atIndex(0));
2469 return true;
2470 }
2471
2472 const SourceInfo &E = S.Current->getSource(OpPC);
2473 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2474
2475 return false;
2476 }
2477
CallVar(InterpState & S,CodePtr OpPC,const Function * Func,uint32_t VarArgSize)2478 inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
2479 uint32_t VarArgSize) {
2480 if (Func->hasThisPointer()) {
2481 size_t ArgSize = Func->getArgSize() + VarArgSize;
2482 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2483 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2484
2485 // If the current function is a lambda static invoker and
2486 // the function we're about to call is a lambda call operator,
2487 // skip the CheckInvoke, since the ThisPtr is a null pointer
2488 // anyway.
2489 if (!(S.Current->getFunction() &&
2490 S.Current->getFunction()->isLambdaStaticInvoker() &&
2491 Func->isLambdaCallOperator())) {
2492 if (!CheckInvoke(S, OpPC, ThisPtr))
2493 return false;
2494 }
2495
2496 if (S.checkingPotentialConstantExpression())
2497 return false;
2498 }
2499
2500 if (!CheckCallable(S, OpPC, Func))
2501 return false;
2502
2503 if (!CheckCallDepth(S, OpPC))
2504 return false;
2505
2506 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2507 InterpFrame *FrameBefore = S.Current;
2508 S.Current = NewFrame.get();
2509
2510 APValue CallResult;
2511 // Note that we cannot assert(CallResult.hasValue()) here since
2512 // Ret() above only sets the APValue if the curent frame doesn't
2513 // have a caller set.
2514 if (Interpret(S, CallResult)) {
2515 NewFrame.release(); // Frame was delete'd already.
2516 assert(S.Current == FrameBefore);
2517 return true;
2518 }
2519
2520 // Interpreting the function failed somehow. Reset to
2521 // previous state.
2522 S.Current = FrameBefore;
2523 return false;
2524
2525 return false;
2526 }
2527
Call(InterpState & S,CodePtr OpPC,const Function * Func,uint32_t VarArgSize)2528 inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
2529 uint32_t VarArgSize) {
2530 if (Func->hasThisPointer()) {
2531 size_t ArgSize = Func->getArgSize() + VarArgSize;
2532 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2533
2534 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2535
2536 // If the current function is a lambda static invoker and
2537 // the function we're about to call is a lambda call operator,
2538 // skip the CheckInvoke, since the ThisPtr is a null pointer
2539 // anyway.
2540 if (!(S.Current->getFunction() &&
2541 S.Current->getFunction()->isLambdaStaticInvoker() &&
2542 Func->isLambdaCallOperator())) {
2543 if (!CheckInvoke(S, OpPC, ThisPtr))
2544 return false;
2545 }
2546 }
2547
2548 if (!CheckCallable(S, OpPC, Func))
2549 return false;
2550
2551 if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
2552 return false;
2553
2554 if (!CheckCallDepth(S, OpPC))
2555 return false;
2556
2557 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2558 InterpFrame *FrameBefore = S.Current;
2559 S.Current = NewFrame.get();
2560
2561 APValue CallResult;
2562 // Note that we cannot assert(CallResult.hasValue()) here since
2563 // Ret() above only sets the APValue if the curent frame doesn't
2564 // have a caller set.
2565 if (Interpret(S, CallResult)) {
2566 NewFrame.release(); // Frame was delete'd already.
2567 assert(S.Current == FrameBefore);
2568 return true;
2569 }
2570
2571 // Interpreting the function failed somehow. Reset to
2572 // previous state.
2573 S.Current = FrameBefore;
2574 return false;
2575 }
2576
CallVirt(InterpState & S,CodePtr OpPC,const Function * Func,uint32_t VarArgSize)2577 inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
2578 uint32_t VarArgSize) {
2579 assert(Func->hasThisPointer());
2580 assert(Func->isVirtual());
2581 size_t ArgSize = Func->getArgSize() + VarArgSize;
2582 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2583 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2584
2585 QualType DynamicType = ThisPtr.getDeclDesc()->getType();
2586 const CXXRecordDecl *DynamicDecl;
2587 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
2588 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2589 else
2590 DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
2591 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
2592 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
2593 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2594 DynamicDecl, StaticDecl, InitialFunction);
2595
2596 if (Overrider != InitialFunction) {
2597 // DR1872: An instantiated virtual constexpr function can't be called in a
2598 // constant expression (prior to C++20). We can still constant-fold such a
2599 // call.
2600 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2601 const Expr *E = S.Current->getExpr(OpPC);
2602 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
2603 }
2604
2605 Func = S.getContext().getOrCreateFunction(Overrider);
2606
2607 const CXXRecordDecl *ThisFieldDecl =
2608 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2609 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2610 // If the function we call is further DOWN the hierarchy than the
2611 // FieldDesc of our pointer, just get the DeclDesc instead, which
2612 // is the furthest we might go up in the hierarchy.
2613 ThisPtr = ThisPtr.getDeclPtr();
2614 }
2615 }
2616
2617 return Call(S, OpPC, Func, VarArgSize);
2618 }
2619
CallBI(InterpState & S,CodePtr & PC,const Function * Func,const CallExpr * CE)2620 inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
2621 const CallExpr *CE) {
2622 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
2623
2624 InterpFrame *FrameBefore = S.Current;
2625 S.Current = NewFrame.get();
2626
2627 if (InterpretBuiltin(S, PC, Func, CE)) {
2628 NewFrame.release();
2629 return true;
2630 }
2631 S.Current = FrameBefore;
2632 return false;
2633 }
2634
CallPtr(InterpState & S,CodePtr OpPC,uint32_t ArgSize,const CallExpr * CE)2635 inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2636 const CallExpr *CE) {
2637 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
2638
2639 const Function *F = FuncPtr.getFunction();
2640 if (!F) {
2641 const Expr *E = S.Current->getExpr(OpPC);
2642 S.FFDiag(E, diag::note_constexpr_null_callee)
2643 << const_cast<Expr *>(E) << E->getSourceRange();
2644 return false;
2645 }
2646
2647 if (!FuncPtr.isValid())
2648 return false;
2649
2650 assert(F);
2651
2652 // This happens when the call expression has been cast to
2653 // something else, but we don't support that.
2654 if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
2655 S.Ctx.classify(CE->getType()))
2656 return false;
2657
2658 // Check argument nullability state.
2659 if (F->hasNonNullAttr()) {
2660 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2661 return false;
2662 }
2663
2664 assert(ArgSize >= F->getWrittenArgSize());
2665 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2666
2667 // We need to do this explicitly here since we don't have the necessary
2668 // information to do it automatically.
2669 if (F->isThisPointerExplicit())
2670 VarArgSize -= align(primSize(PT_Ptr));
2671
2672 if (F->isVirtual())
2673 return CallVirt(S, OpPC, F, VarArgSize);
2674
2675 return Call(S, OpPC, F, VarArgSize);
2676 }
2677
GetFnPtr(InterpState & S,CodePtr OpPC,const Function * Func)2678 inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2679 assert(Func);
2680 S.Stk.push<FunctionPointer>(Func);
2681 return true;
2682 }
2683
2684 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetIntPtr(InterpState & S,CodePtr OpPC,const Descriptor * Desc)2685 inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2686 const T &IntVal = S.Stk.pop<T>();
2687
2688 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2689 return true;
2690 }
2691
GetMemberPtr(InterpState & S,CodePtr OpPC,const Decl * D)2692 inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {
2693 S.Stk.push<MemberPointer>(D);
2694 return true;
2695 }
2696
GetMemberPtrBase(InterpState & S,CodePtr OpPC)2697 inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
2698 const auto &MP = S.Stk.pop<MemberPointer>();
2699
2700 S.Stk.push<Pointer>(MP.getBase());
2701 return true;
2702 }
2703
GetMemberPtrDecl(InterpState & S,CodePtr OpPC)2704 inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
2705 const auto &MP = S.Stk.pop<MemberPointer>();
2706
2707 const auto *FD = cast<FunctionDecl>(MP.getDecl());
2708 const auto *Func = S.getContext().getOrCreateFunction(FD);
2709
2710 S.Stk.push<FunctionPointer>(Func);
2711 return true;
2712 }
2713
2714 /// Just emit a diagnostic. The expression that caused emission of this
2715 /// op is not valid in a constant context.
Invalid(InterpState & S,CodePtr OpPC)2716 inline bool Invalid(InterpState &S, CodePtr OpPC) {
2717 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2718 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2719 << S.Current->getRange(OpPC);
2720 return false;
2721 }
2722
Unsupported(InterpState & S,CodePtr OpPC)2723 inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2724 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2725 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2726 << S.Current->getRange(OpPC);
2727 return false;
2728 }
2729
2730 /// Do nothing and just abort execution.
Error(InterpState & S,CodePtr OpPC)2731 inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2732
2733 /// Same here, but only for casts.
InvalidCast(InterpState & S,CodePtr OpPC,CastKind Kind)2734 inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
2735 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2736
2737 // FIXME: Support diagnosing other invalid cast kinds.
2738 if (Kind == CastKind::Reinterpret)
2739 S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
2740 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2741 return false;
2742 }
2743
InvalidDeclRef(InterpState & S,CodePtr OpPC,const DeclRefExpr * DR)2744 inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
2745 const DeclRefExpr *DR) {
2746 assert(DR);
2747 return CheckDeclRef(S, OpPC, DR);
2748 }
2749
SizelessVectorElementSize(InterpState & S,CodePtr OpPC)2750 inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
2751 if (S.inConstantContext()) {
2752 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2753 const Expr *E = S.Current->getExpr(OpPC);
2754 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2755 }
2756 return false;
2757 }
2758
Assume(InterpState & S,CodePtr OpPC)2759 inline bool Assume(InterpState &S, CodePtr OpPC) {
2760 const auto Val = S.Stk.pop<Boolean>();
2761
2762 if (Val)
2763 return true;
2764
2765 // Else, diagnose.
2766 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2767 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2768 return false;
2769 }
2770
2771 template <PrimType Name, class T = typename PrimConv<Name>::T>
OffsetOf(InterpState & S,CodePtr OpPC,const OffsetOfExpr * E)2772 inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2773 llvm::SmallVector<int64_t> ArrayIndices;
2774 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2775 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2776
2777 int64_t Result;
2778 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2779 return false;
2780
2781 S.Stk.push<T>(T::from(Result));
2782
2783 return true;
2784 }
2785
2786 template <PrimType Name, class T = typename PrimConv<Name>::T>
CheckNonNullArg(InterpState & S,CodePtr OpPC)2787 inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2788 const T &Arg = S.Stk.peek<T>();
2789 if (!Arg.isZero())
2790 return true;
2791
2792 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2793 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2794
2795 return false;
2796 }
2797
2798 void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
2799 const APSInt &Value);
2800
2801 template <PrimType Name, class T = typename PrimConv<Name>::T>
CheckEnumValue(InterpState & S,CodePtr OpPC,const EnumDecl * ED)2802 inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
2803 assert(ED);
2804 assert(!ED->isFixed());
2805 const APSInt Val = S.Stk.peek<T>().toAPSInt();
2806
2807 if (S.inConstantContext())
2808 diagnoseEnumValue(S, OpPC, ED, Val);
2809 return true;
2810 }
2811
2812 /// OldPtr -> Integer -> NewPtr.
2813 template <PrimType TIn, PrimType TOut>
DecayPtr(InterpState & S,CodePtr OpPC)2814 inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2815 static_assert(isPtrType(TIn) && isPtrType(TOut));
2816 using FromT = typename PrimConv<TIn>::T;
2817 using ToT = typename PrimConv<TOut>::T;
2818
2819 const FromT &OldPtr = S.Stk.pop<FromT>();
2820 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2821 return true;
2822 }
2823
CheckDecl(InterpState & S,CodePtr OpPC,const VarDecl * VD)2824 inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
2825 // An expression E is a core constant expression unless the evaluation of E
2826 // would evaluate one of the following: [C++23] - a control flow that passes
2827 // through a declaration of a variable with static or thread storage duration
2828 // unless that variable is usable in constant expressions.
2829 assert(VD->isLocalVarDecl() &&
2830 VD->isStaticLocal()); // Checked before emitting this.
2831
2832 if (VD == S.EvaluatingDecl)
2833 return true;
2834
2835 if (!VD->isUsableInConstantExpressions(S.getCtx())) {
2836 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
2837 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
2838 return false;
2839 }
2840 return true;
2841 }
2842
Alloc(InterpState & S,CodePtr OpPC,const Descriptor * Desc)2843 inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2844 assert(Desc);
2845
2846 if (!CheckDynamicMemoryAllocation(S, OpPC))
2847 return false;
2848
2849 DynamicAllocator &Allocator = S.getAllocator();
2850 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID());
2851 assert(B);
2852
2853 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2854
2855 return true;
2856 }
2857
2858 template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
AllocN(InterpState & S,CodePtr OpPC,PrimType T,const Expr * Source,bool IsNoThrow)2859 inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
2860 bool IsNoThrow) {
2861 if (!CheckDynamicMemoryAllocation(S, OpPC))
2862 return false;
2863
2864 SizeT NumElements = S.Stk.pop<SizeT>();
2865 if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
2866 if (!IsNoThrow)
2867 return false;
2868
2869 // If this failed and is nothrow, just return a null ptr.
2870 S.Stk.push<Pointer>(0, nullptr);
2871 return true;
2872 }
2873
2874 DynamicAllocator &Allocator = S.getAllocator();
2875 Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
2876 S.Ctx.getEvalID());
2877 assert(B);
2878 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2879
2880 return true;
2881 }
2882
2883 template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
AllocCN(InterpState & S,CodePtr OpPC,const Descriptor * ElementDesc,bool IsNoThrow)2884 inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
2885 bool IsNoThrow) {
2886 if (!CheckDynamicMemoryAllocation(S, OpPC))
2887 return false;
2888
2889 SizeT NumElements = S.Stk.pop<SizeT>();
2890 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
2891 IsNoThrow)) {
2892 if (!IsNoThrow)
2893 return false;
2894
2895 // If this failed and is nothrow, just return a null ptr.
2896 S.Stk.push<Pointer>(0, ElementDesc);
2897 return true;
2898 }
2899
2900 DynamicAllocator &Allocator = S.getAllocator();
2901 Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
2902 S.Ctx.getEvalID());
2903 assert(B);
2904
2905 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2906
2907 return true;
2908 }
2909
2910 bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B);
Free(InterpState & S,CodePtr OpPC,bool DeleteIsArrayForm)2911 static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
2912 if (!CheckDynamicMemoryAllocation(S, OpPC))
2913 return false;
2914
2915 const Expr *Source = nullptr;
2916 const Block *BlockToDelete = nullptr;
2917 {
2918 // Extra scope for this so the block doesn't have this pointer
2919 // pointing to it when we destroy it.
2920 const Pointer &Ptr = S.Stk.pop<Pointer>();
2921
2922 // Deleteing nullptr is always fine.
2923 if (Ptr.isZero())
2924 return true;
2925
2926 if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
2927 const SourceInfo &Loc = S.Current->getSource(OpPC);
2928 S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
2929 << Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd();
2930 return false;
2931 }
2932
2933 Source = Ptr.getDeclDesc()->asExpr();
2934 BlockToDelete = Ptr.block();
2935
2936 if (!CheckDeleteSource(S, OpPC, Source, Ptr))
2937 return false;
2938 }
2939 assert(Source);
2940 assert(BlockToDelete);
2941
2942 // Invoke destructors before deallocating the memory.
2943 if (!RunDestructors(S, OpPC, BlockToDelete))
2944 return false;
2945
2946 DynamicAllocator &Allocator = S.getAllocator();
2947 bool WasArrayAlloc = Allocator.isArrayAllocation(Source);
2948 const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
2949
2950 if (!Allocator.deallocate(Source, BlockToDelete, S)) {
2951 // Nothing has been deallocated, this must be a double-delete.
2952 const SourceInfo &Loc = S.Current->getSource(OpPC);
2953 S.FFDiag(Loc, diag::note_constexpr_double_delete);
2954 return false;
2955 }
2956 return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm,
2957 BlockDesc, Source);
2958 }
2959
2960 //===----------------------------------------------------------------------===//
2961 // Read opcode arguments
2962 //===----------------------------------------------------------------------===//
2963
ReadArg(InterpState & S,CodePtr & OpPC)2964 template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2965 if constexpr (std::is_pointer<T>::value) {
2966 uint32_t ID = OpPC.read<uint32_t>();
2967 return reinterpret_cast<T>(S.P.getNativePointer(ID));
2968 } else {
2969 return OpPC.read<T>();
2970 }
2971 }
2972
2973 template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
2974 Floating F = Floating::deserialize(*OpPC);
2975 OpPC += align(F.bytesToSerialize());
2976 return F;
2977 }
2978
2979 template <>
2980 inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
2981 CodePtr &OpPC) {
2982 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
2983 OpPC += align(I.bytesToSerialize());
2984 return I;
2985 }
2986
2987 template <>
2988 inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
2989 CodePtr &OpPC) {
2990 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
2991 OpPC += align(I.bytesToSerialize());
2992 return I;
2993 }
2994
2995 } // namespace interp
2996 } // namespace clang
2997
2998 #endif
2999