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