xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Interp.h (revision 36b606ae6aa4b24061096ba18582e0a08ccd5dba)
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