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