clang: lib/AST/ByteCode/Interp.h Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H

14#define LLVM_CLANG_AST_INTERP_INTERP_H

15

16#include "../ExprConstShared.h"

35#include "llvm/ADT/APFloat.h"

36#include "llvm/ADT/APSInt.h"

37#include <type_traits>

38

40namespace interp {

41

42using APSInt = llvm::APSInt;

44

45

47

48

50

51

54

55

58

59

62

63

66

67

70

71

74

75

76

78 uint32_t Offset);

79

80

82

83

85

86

88

89

93

96

98

99

101

102

104

105

107

108

110

111

112

114

115

117

118

120

121

123 const CallExpr *CE, unsigned ArgSize);

124

125

126

128

129

133 const Expr *NewExpr);

134

135

136

139

140

141

144

145

147

149 uint32_t VarArgSize);

151 uint32_t VarArgSize);

153 uint32_t VarArgSize);

155 const CallExpr *CE, uint32_t BuiltinID);

161 bool TargetIsUCharOrByte);

162

163template

165 const Expr *E = S.Current->getExpr(OpPC);

166 S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();

167 return S.noteUndefinedBehavior();

168}

170 const FixedPoint &FP);

171

173

174

175template <ShiftDir Dir, typename LT, typename RT>

177 unsigned Bits) {

178 if (RHS.isNegative()) {

179 const SourceInfo &Loc = S.Current->getSource(OpPC);

180 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();

181 if (!S.noteUndefinedBehavior())

182 return false;

183 }

184

185

186

187 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {

188 const Expr *E = S.Current->getExpr(OpPC);

189 const APSInt Val = RHS.toAPSInt();

191 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;

192 if (!S.noteUndefinedBehavior())

193 return false;

194 }

195

197 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {

198 const Expr *E = S.Current->getExpr(OpPC);

199

200

201 if (LHS.isNegative()) {

202 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();

203 if (!S.noteUndefinedBehavior())

204 return false;

205 } else if (LHS.toUnsigned().countLeadingZeros() <

206 static_cast<unsigned>(RHS)) {

207 S.CCEDiag(E, diag::note_constexpr_lshift_discards);

208 if (!S.noteUndefinedBehavior())

209 return false;

210 }

211 }

212 }

213

214

215

216

217 return true;

218}

219

220

221template

223 if (RHS.isZero()) {

224 const auto *Op = cast(S.Current->getExpr(OpPC));

225 if constexpr (std::is_same_v<T, Floating>) {

226 S.CCEDiag(Op, diag::note_expr_divide_by_zero)

227 << Op->getRHS()->getSourceRange();

228 return true;

229 }

230

231 S.FFDiag(Op, diag::note_expr_divide_by_zero)

232 << Op->getRHS()->getSourceRange();

233 return false;

234 }

235

236 if constexpr (!std::is_same_v<T, FixedPoint>) {

237 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {

238 APSInt LHSInt = LHS.toAPSInt();

240 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);

241 const SourceInfo &Loc = S.Current->getSource(OpPC);

242 const Expr *E = S.Current->getExpr(OpPC);

243 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();

244 return false;

245 }

246 }

247 return true;

248}

249

250template

252 unsigned ElemSize, bool IsNoThrow) {

253

254

255

256

257

258 if ((NumElements->bitWidth() - NumElements->isSigned()) <

260 return true;

261

262

263

264

265

267 assert(MaxElements.isPositive());

268 if (NumElements->toAPSInt().getActiveBits() >

270 *NumElements > MaxElements) {

271 if (!IsNoThrow) {

272 const SourceInfo &Loc = S.Current->getSource(OpPC);

273

274 if (NumElements->isSigned() && NumElements->isNegative()) {

275 S.FFDiag(Loc, diag::note_constexpr_new_negative)

276 << NumElements->toDiagnosticString(S.getASTContext());

277 } else {

278 S.FFDiag(Loc, diag::note_constexpr_new_too_large)

279 << NumElements->toDiagnosticString(S.getASTContext());

280 }

281 }

282 return false;

283 }

284 return true;

285}

286

287

288

290 APFloat::opStatus Status, FPOptions FPO);

291

292

294

295

297

298

299bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,

301

302

305

306inline bool Invalid(InterpState &S, CodePtr OpPC);

307

309

310

311

312

313

315 const Function *Func);

316

317template <PrimType Name, class T = typename PrimConv::T>

319 const T &Ret = S.Stk.pop<T>();

320

321 assert(S.Current);

322 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");

323 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)

325

326 if (InterpFrame *Caller = S.Current->Caller) {

327 PC = S.Current->getRetPC();

328 delete S.Current;

329 S.Current = Caller;

330 S.Stk.push<T>(Ret);

331 } else {

332 delete S.Current;

333 S.Current = nullptr;

334

335

336 }

337 return true;

338}

339

341 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");

342

343 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)

345

346 if (InterpFrame *Caller = S.Current->Caller) {

347 PC = S.Current->getRetPC();

348 delete S.Current;

349 S.Current = Caller;

350 } else {

351 delete S.Current;

352 S.Current = nullptr;

353 }

354 return true;

355}

356

357

358

359

360

362 template class OpAP>

364 const T &RHS) {

365

367 if (!OpFW(LHS, RHS, Bits, &Result)) {

369 return true;

370 }

371

373

374

375 if constexpr (std::is_same_v<T, FixedPoint>)

377

378

380

381

382 const Expr *E = S.Current->getExpr(OpPC);

384 if (S.checkingForUndefinedBehavior()) {

387 .toString(Trunc, 10, Result.isSigned(), false,

388 true, true);

390 S.report(Loc, diag::warn_integer_constant_overflow)

392 }

393

395 S.Stk.pop<T>();

396 return false;

397 }

398 return true;

399}

400

401template <PrimType Name, class T = typename PrimConv::T>

403 const T &RHS = S.Stk.pop<T>();

404 const T &LHS = S.Stk.pop<T>();

405 const unsigned Bits = RHS.bitWidth() + 1;

406 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);

407}

408

411 if (RM == llvm::RoundingMode::Dynamic)

412 return llvm::RoundingMode::NearestTiesToEven;

413 return RM;

414}

415

419

425}

426

427template <PrimType Name, class T = typename PrimConv::T>

429 const T &RHS = S.Stk.pop<T>();

430 const T &LHS = S.Stk.pop<T>();

431 const unsigned Bits = RHS.bitWidth() + 1;

432 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);

433}

434

438

444}

445

446template <PrimType Name, class T = typename PrimConv::T>

448 const T &RHS = S.Stk.pop<T>();

449 const T &LHS = S.Stk.pop<T>();

450 const unsigned Bits = RHS.bitWidth() * 2;

451 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);

452}

453

457

463}

464

465template <PrimType Name, class T = typename PrimConv::T>

470

471 if constexpr (std::is_same_v<T, Floating>) {

473 APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();

476

477 APFloat ResR(A.getSemantics());

478 APFloat ResI(A.getSemantics());

480

481

483 Result.atIndex(0).initialize();

485 Result.atIndex(1).initialize();

487 } else {

488

489 const T &LHSR = LHS.atIndex(0).deref<T>();

490 const T &LHSI = LHS.atIndex(1).deref<T>();

493 unsigned Bits = LHSR.bitWidth();

494

495

496 T A;

497 if (T::mul(LHSR, RHSR, Bits, &A))

498 return false;

499 T B;

500 if (T::mul(LHSI, RHSI, Bits, &B))

501 return false;

502 if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))

503 return false;

504 Result.atIndex(0).initialize();

505

506

507 if (T::mul(LHSR, RHSI, Bits, &A))

508 return false;

509 if (T::mul(LHSI, RHSR, Bits, &B))

510 return false;

511 if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))

512 return false;

513 Result.atIndex(1).initialize();

515 }

516

517 return true;

518}

519

520template <PrimType Name, class T = typename PrimConv::T>

525

526 if constexpr (std::is_same_v<T, Floating>) {

528 APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();

531

532 APFloat ResR(A.getSemantics());

533 APFloat ResI(A.getSemantics());

535

536

538 Result.atIndex(0).initialize();

540 Result.atIndex(1).initialize();

542 } else {

543

544 const T &LHSR = LHS.atIndex(0).deref<T>();

545 const T &LHSI = LHS.atIndex(1).deref<T>();

548 unsigned Bits = LHSR.bitWidth();

550

553 const SourceInfo &E = S.Current->getSource(OpPC);

554 S.FFDiag(E, diag::note_expr_divide_by_zero);

555 return false;

556 }

557

558

559 T A, B;

560 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {

561

562 }

563 T Den;

564 if (T::add(A, B, Bits, &Den))

565 return false;

566

568 const SourceInfo &E = S.Current->getSource(OpPC);

569 S.FFDiag(E, diag::note_expr_divide_by_zero);

570 return false;

571 }

572

573

574 T &ResultR = Result.atIndex(0).deref<T>();

575 T &ResultI = Result.atIndex(1).deref<T>();

576

577 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))

578 return false;

579 if (T::add(A, B, Bits, &ResultR))

580 return false;

581 if (T::div(ResultR, Den, Bits, &ResultR))

582 return false;

583 Result.atIndex(0).initialize();

584

585

586 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))

587 return false;

588 if (T::sub(A, B, Bits, &ResultI))

589 return false;

590 if (T::div(ResultI, Den, Bits, &ResultI))

591 return false;

592 Result.atIndex(1).initialize();

594 }

595

596 return true;

597}

598

599

600

601

602template <PrimType Name, class T = typename PrimConv::T>

604 const T &RHS = S.Stk.pop<T>();

605 const T &LHS = S.Stk.pop<T>();

606

607 unsigned Bits = RHS.bitWidth();

609 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {

611 return true;

612 }

613 return false;

614}

615

616

617

618

619template <PrimType Name, class T = typename PrimConv::T>

621 const T &RHS = S.Stk.pop<T>();

622 const T &LHS = S.Stk.pop<T>();

623

624 unsigned Bits = RHS.bitWidth();

626 if (!T::bitOr(LHS, RHS, Bits, &Result)) {

628 return true;

629 }

630 return false;

631}

632

633

634

635

636template <PrimType Name, class T = typename PrimConv::T>

638 const T &RHS = S.Stk.pop<T>();

639 const T &LHS = S.Stk.pop<T>();

640

641 unsigned Bits = RHS.bitWidth();

643 if (!T::bitXor(LHS, RHS, Bits, &Result)) {

645 return true;

646 }

647 return false;

648}

649

650

651

652

653template <PrimType Name, class T = typename PrimConv::T>

655 const T &RHS = S.Stk.pop<T>();

656 const T &LHS = S.Stk.pop<T>();

657

659 return false;

660

661 const unsigned Bits = RHS.bitWidth() * 2;

663 if (!T::rem(LHS, RHS, Bits, &Result)) {

665 return true;

666 }

667 return false;

668}

669

670

671

672

673template <PrimType Name, class T = typename PrimConv::T>

675 const T &RHS = S.Stk.pop<T>();

676 const T &LHS = S.Stk.pop<T>();

677

679 return false;

680

681 const unsigned Bits = RHS.bitWidth() * 2;

683 if (!T::div(LHS, RHS, Bits, &Result)) {

685 return true;

686 }

687

688 if constexpr (std::is_same_v<T, FixedPoint>) {

691 return true;

692 }

693 }

694 return false;

695}

696

700

702 return false;

703

709}

710

711

712

713

714

716 const auto &Val = S.Stk.pop<Boolean>();

717 S.Stk.push<Boolean>(!Val);

718 return true;

719}

720

721

722

723

724

725template <PrimType Name, class T = typename PrimConv::T>

727 const T &Value = S.Stk.pop<T>();

729

732 return true;

733 }

734

736 "don't expect other types to fail at constexpr negation");

738

740 const Expr *E = S.Current->getExpr(OpPC);

742

743 if (S.checkingForUndefinedBehavior()) {

745 NegatedValue.trunc(Result.bitWidth())

746 .toString(Trunc, 10, Result.isSigned(), false,

747 true, true);

749 S.report(Loc, diag::warn_integer_constant_overflow)

751 return true;

752 }

753

755}

756

760};

764};

765

766template <typename T, IncDecOp Op, PushVal DoPush>

769

770 if constexpr (std::is_same_v<T, Boolean>) {

773 }

774

777

779 S.Stk.push<T>(Value);

780

784 return true;

785 }

786 } else {

789 return true;

790 }

791 }

792

793

794

795 unsigned Bits = Value.bitWidth() + 1;

798 APResult = ++Value.toAPSInt(Bits);

799 else

800 APResult = --Value.toAPSInt(Bits);

801

802

803 const Expr *E = S.Current->getExpr(OpPC);

805 if (S.checkingForUndefinedBehavior()) {

807 APResult.trunc(Result.bitWidth())

808 .toString(Trunc, 10, Result.isSigned(), false,

809 true, true);

811 S.report(Loc, diag::warn_integer_constant_overflow)

813 return true;

814 }

815

817}

818

819

820

821

822

823template <PrimType Name, class T = typename PrimConv::T>

827 return false;

828

829 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);

830}

831

832

833

834

835template <PrimType Name, class T = typename PrimConv::T>

839 return false;

840

841 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);

842}

843

844

845

846

847

848template <PrimType Name, class T = typename PrimConv::T>

852 return false;

853

854 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);

855}

856

857

858

859

860template <PrimType Name, class T = typename PrimConv::T>

864 return false;

865

866 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);

867}

868

869template <IncDecOp Op, PushVal DoPush>

871 uint32_t FPOI) {

874

877

879 llvm::APFloat::opStatus Status;

882 else

884

886

888}

889

893 return false;

894

895 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);

896}

897

901 return false;

902

903 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);

904}

905

909 return false;

910

911 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);

912}

913

917 return false;

918

919 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);

920}

921

922

923

924template <PrimType Name, class T = typename PrimConv::T>

926 const T &Val = S.Stk.pop<T>();

928 if (!T::comp(Val, &Result)) {

930 return true;

931 }

932

933 return false;

934}

935

936

937

938

939

941

942template

944 assert((!std::is_same_v<T, MemberPointer>) &&

945 "Non-equality comparisons on member pointer types should already be "

946 "rejected in Sema.");

948 const T &RHS = S.Stk.pop<T>();

949 const T &LHS = S.Stk.pop<T>();

950 S.Stk.push(BoolT::from(Fn(LHS.compare(RHS))));

951 return true;

952}

953

954template

956 return CmpHelper(S, OpPC, Fn);

957}

958

959

960template <>

965

966 const SourceInfo &Loc = S.Current->getSource(OpPC);

967 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)

970 return false;

971}

972

973template <>

978

979

980 for (const auto &FP : {LHS, RHS}) {

981 if (FP.isWeak()) {

982 const SourceInfo &Loc = S.Current->getSource(OpPC);

983 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)

985 return false;

986 }

987 }

988

990 return true;

991}

992

993template <>

998

1000 const SourceInfo &Loc = S.Current->getSource(OpPC);

1001 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)

1004 return false;

1005 } else {

1006 unsigned VL = LHS.getByteOffset();

1008 S.Stk.push(BoolT::from(Fn(Compare(VL, VR))));

1009 return true;

1010 }

1011}

1012

1013template <>

1018

1019 if (LHS.isZero() && RHS.isZero()) {

1021 return true;

1022 }

1023

1024

1025 for (const auto &P : {LHS, RHS}) {

1026 if (P.isZero())

1027 continue;

1028 if (P.isWeak()) {

1029 const SourceInfo &Loc = S.Current->getSource(OpPC);

1030 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)

1032 return false;

1033 }

1034 }

1035

1037 unsigned VL = LHS.getByteOffset();

1039

1040

1041

1042

1043

1044 if (!LHS.isZero() && LHS.isArrayRoot())

1045 VL = LHS.atIndex(0).getByteOffset();

1048

1049 S.Stk.push(BoolT::from(Fn(Compare(VL, VR))));

1050 return true;

1051 }

1052

1055 const SourceInfo &Loc = S.Current->getSource(OpPC);

1056 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)

1058 return false;

1059 } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&

1060 LHS.getOffset() == 0) {

1061 const SourceInfo &Loc = S.Current->getSource(OpPC);

1062 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)

1064 return false;

1065 }

1066

1067 bool BothNonNull = !LHS.isZero() && !RHS.isZero();

1068

1069 for (const auto &P : {LHS, RHS}) {

1070 if (P.isZero())

1071 continue;

1072 if (BothNonNull && P.pointsToLiteral()) {

1073 const SourceInfo &Loc = S.Current->getSource(OpPC);

1074 S.FFDiag(Loc, diag::note_constexpr_literal_comparison);

1075 return false;

1076 }

1077 }

1078

1080 return true;

1081}

1082

1083template <>

1088

1089

1090

1091 for (const auto &MP : {LHS, RHS}) {

1092 if (MP.isWeak()) {

1093 const SourceInfo &Loc = S.Current->getSource(OpPC);

1094 S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)

1095 << MP.getMemberFunction();

1096 return false;

1097 }

1098 }

1099

1100

1101

1102

1103 if (LHS.isZero() && RHS.isZero()) {

1105 return true;

1106 }

1107 if (LHS.isZero() || RHS.isZero()) {

1109 return true;

1110 }

1111

1112

1113 for (const auto &MP : {LHS, RHS}) {

1114 if (const CXXMethodDecl *MD = MP.getMemberFunction();

1116 const SourceInfo &Loc = S.Current->getSource(OpPC);

1117 S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;

1118 }

1119 }

1120

1122 return true;

1123}

1124

1125template <PrimType Name, class T = typename PrimConv::T>

1129 });

1130}

1131

1132template <PrimType Name, class T = typename PrimConv::T>

1134 const T &RHS = S.Stk.pop<T>();

1135 const T &LHS = S.Stk.pop<T>();

1137

1140

1141 const SourceInfo &Loc = S.Current->getSource(OpPC);

1142 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)

1145 return false;

1146 }

1147

1148 assert(CmpInfo);

1149 const auto *CmpValueInfo =

1151 assert(CmpValueInfo);

1152 assert(CmpValueInfo->hasValidIntValue());

1154}

1155

1156template <PrimType Name, class T = typename PrimConv::T>

1160 });

1161}

1162

1163template <PrimType Name, class T = typename PrimConv::T>

1167 });

1168}

1169

1170template <PrimType Name, class T = typename PrimConv::T>

1175 });

1176}

1177

1178template <PrimType Name, class T = typename PrimConv::T>

1182 });

1183}

1184

1185template <PrimType Name, class T = typename PrimConv::T>

1190 });

1191}

1192

1193

1194

1195

1196

1197template <PrimType Name, class T = typename PrimConv::T>

1199 const T RHS = S.Stk.pop<T>();

1200 const T LHS = S.Stk.pop<T>();

1201 const T Value = S.Stk.pop<T>();

1202

1203 S.Stk.push<bool>(LHS <= Value && Value <= RHS);

1204 return true;

1205}

1206

1207

1208

1209

1210

1211template <PrimType Name, class T = typename PrimConv::T>

1213 S.Stk.push<T>(S.Stk.peek<T>());

1214 return true;

1215}

1216

1217template <PrimType Name, class T = typename PrimConv::T>

1219 S.Stk.pop<T>();

1220 return true;

1221}

1222

1223

1224template <PrimType TopName, PrimType BottomName>

1228

1229 const auto &Top = S.Stk.pop();

1230 const auto &Bottom = S.Stk.pop();

1231

1232 S.Stk.push(Top);

1233 S.Stk.push(Bottom);

1234

1235 return true;

1236}

1237

1238

1239

1240

1241

1242template <PrimType Name, class T = typename PrimConv::T>

1244 S.Stk.push<T>(Arg);

1245 return true;

1246}

1247

1248

1249

1250

1251

1252template <PrimType Name, class T = typename PrimConv::T>

1254 const Pointer &Ptr = S.Current->getLocalPointer(I);

1256 return false;

1257 S.Stk.push<T>(Ptr.deref<T>());

1258 return true;

1259}

1260

1261

1262

1263

1264template <PrimType Name, class T = typename PrimConv::T>

1266 S.Current->setLocal<T>(I, S.Stk.pop<T>());

1267 return true;

1268}

1269

1270template <PrimType Name, class T = typename PrimConv::T>

1272 if (S.checkingPotentialConstantExpression()) {

1273 return false;

1274 }

1275 S.Stk.push<T>(S.Current->getParam<T>(I));

1276 return true;

1277}

1278

1279template <PrimType Name, class T = typename PrimConv::T>

1281 S.Current->setParam<T>(I, S.Stk.pop<T>());

1282 return true;

1283}

1284

1285

1286

1287template <PrimType Name, class T = typename PrimConv::T>

1291 return false;

1293 return false;

1296 return false;

1297 S.Stk.push<T>(Field.deref<T>());

1298 return true;

1299}

1300

1301template <PrimType Name, class T = typename PrimConv::T>

1303 const T &Value = S.Stk.pop<T>();

1306 return false;

1308 return false;

1309 const Pointer &Field = Obj.atField(I);

1311 return false;

1312 Field.initialize();

1313 Field.deref<T>() = Value;

1314 return true;

1315}

1316

1317

1318

1319template <PrimType Name, class T = typename PrimConv::T>

1323 return false;

1325 return false;

1328 return false;

1329 S.Stk.push<T>(Field.deref<T>());

1330 return true;

1331}

1332

1333template <PrimType Name, class T = typename PrimConv::T>

1335 if (S.checkingPotentialConstantExpression())

1336 return false;

1337 const Pointer &This = S.Current->getThis();

1339 return false;

1342 return false;

1343 S.Stk.push<T>(Field.deref<T>());

1344 return true;

1345}

1346

1347template <PrimType Name, class T = typename PrimConv::T>

1349 if (S.checkingPotentialConstantExpression())

1350 return false;

1351 const T &Value = S.Stk.pop<T>();

1352 const Pointer &This = S.Current->getThis();

1354 return false;

1357 return false;

1358 Field.deref<T>() = Value;

1359 return true;

1360}

1361

1362template <PrimType Name, class T = typename PrimConv::T>

1364 const Pointer &Ptr = S.P.getPtrGlobal(I);

1366 return false;

1368 return false;

1369

1370

1371

1373 return false;

1374

1375 S.Stk.push<T>(Ptr.deref<T>());

1376 return true;

1377}

1378

1379

1380template <PrimType Name, class T = typename PrimConv::T>

1382 const Pointer &Ptr = S.P.getPtrGlobal(I);

1384 return false;

1385 S.Stk.push<T>(Ptr.deref<T>());

1386 return true;

1387}

1388

1389template <PrimType Name, class T = typename PrimConv::T>

1391

1392 return false;

1393}

1394

1395template <PrimType Name, class T = typename PrimConv::T>

1397 const Pointer &P = S.P.getGlobal(I);

1398 P.deref<T>() = S.Stk.pop<T>();

1399 P.initialize();

1400 return true;

1401}

1402

1403

1404

1405

1406template <PrimType Name, class T = typename PrimConv::T>

1409 const Pointer &Ptr = S.P.getGlobal(I);

1410

1411 const T Value = S.Stk.peek<T>();

1414 *Cached = APV;

1415

1417

1418 S.SeenGlobalTemporaries.push_back(

1420

1421 Ptr.deref<T>() = S.Stk.pop<T>();

1423 return true;

1424}

1425

1426

1427

1428

1431 assert(Temp);

1434

1435 S.SeenGlobalTemporaries.push_back(

1436 std::make_pair(P.getDeclDesc()->asExpr(), Temp));

1437

1438 if (std::optional APV =

1440 *Cached = *APV;

1441 return true;

1442 }

1443

1444 return false;

1445}

1446

1447template <PrimType Name, class T = typename PrimConv::T>

1449 if (S.checkingPotentialConstantExpression())

1450 return false;

1451 const Pointer &This = S.Current->getThis();

1453 return false;

1455 Field.deref<T>() = S.Stk.pop<T>();

1456 Field.activate();

1457 Field.initialize();

1458 return true;

1459}

1460

1461

1462

1463template <PrimType Name, class T = typename PrimConv::T>

1465 uint32_t FieldOffset) {

1466 assert(F->isBitField());

1467 if (S.checkingPotentialConstantExpression())

1468 return false;

1469 const Pointer &This = S.Current->getThis();

1471 return false;

1472 const Pointer &Field = This.atField(FieldOffset);

1473 const auto &Value = S.Stk.pop<T>();

1474 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());

1475 Field.initialize();

1476 return true;

1477}

1478

1479

1480

1481

1482template <PrimType Name, class T = typename PrimConv::T>

1484 const T &Value = S.Stk.pop<T>();

1485 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);

1486 Field.deref<T>() = Value;

1487 Field.activate();

1488 Field.initialize();

1489 return true;

1490}

1491

1492template <PrimType Name, class T = typename PrimConv::T>

1494 assert(F->isBitField());

1495 const T &Value = S.Stk.pop<T>();

1496 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);

1497 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());

1498 Field.activate();

1499 Field.initialize();

1500 return true;

1501}

1502

1503

1504

1505

1506

1508 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));

1509 return true;

1510}

1511

1513 if (S.checkingPotentialConstantExpression()) {

1514 return false;

1515 }

1516 S.Stk.push<Pointer>(S.Current->getParamPointer(I));

1517 return true;

1518}

1519

1521 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));

1522 return true;

1523}

1524

1525

1526

1527bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);

1528bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);

1529

1531 if (S.checkingPotentialConstantExpression())

1532 return false;

1533 const Pointer &This = S.Current->getThis();

1535 return false;

1537 return true;

1538}

1539

1543 return false;

1545 return false;

1548 Field.activate();

1549 S.Stk.push<Pointer>(std::move(Field));

1550 return true;

1551}

1552

1554 if (S.checkingPotentialConstantExpression())

1555 return false;

1556 const Pointer &This = S.Current->getThis();

1558 return false;

1560 This.deactivate();

1561 Field.activate();

1562 S.Stk.push<Pointer>(std::move(Field));

1563 return true;

1564}

1565

1569 return false;

1571 return false;

1573 return false;

1574

1576 return true;

1577}

1578

1582 return false;

1583

1586 return true;

1587 }

1588

1590 return false;

1592 if (Result.isPastEnd() || Result.isBaseClass())

1593 return false;

1595 return true;

1596}

1597

1600

1602 return false;

1603

1606 return true;

1607 }

1608

1610 return false;

1612 if (Result.isPastEnd() || Result.isBaseClass())

1613 return false;

1615 return true;

1616}

1617

1620 S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));

1621 return true;

1622}

1623

1625 if (S.checkingPotentialConstantExpression())

1626 return false;

1627 const Pointer &This = S.Current->getThis();

1629 return false;

1631 return true;

1632}

1633

1639 }

1640 return true;

1641}

1642

1648 }

1649 return true;

1650}

1651

1653 S.Stk.dump();

1654 return true;

1655}

1656

1660 while (Base.isBaseClass())

1662

1663 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);

1664 S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));

1665 return true;

1666}

1667

1670 assert(D);

1673 return false;

1675}

1676

1679 assert(D);

1680 if (S.checkingPotentialConstantExpression())

1681 return false;

1682 const Pointer &This = S.Current->getThis();

1684 return false;

1685 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());

1686}

1687

1688

1689

1690

1691

1692template <PrimType Name, class T = typename PrimConv::T>

1696 return false;

1698 return false;

1699 S.Stk.push<T>(Ptr.deref<T>());

1700 return true;

1701}

1702

1703template <PrimType Name, class T = typename PrimConv::T>

1707 return false;

1709 return false;

1710 S.Stk.push<T>(Ptr.deref<T>());

1711 return true;

1712}

1713

1714template <PrimType Name, class T = typename PrimConv::T>

1716 const T &Value = S.Stk.pop<T>();

1719 return false;

1720 if (Ptr.canBeInitialized()) {

1722 Ptr.activate();

1723 }

1724 Ptr.deref<T>() = Value;

1725 return true;

1726}

1727

1728template <PrimType Name, class T = typename PrimConv::T>

1730 const T &Value = S.Stk.pop<T>();

1733 return false;

1734 if (Ptr.canBeInitialized()) {

1736 Ptr.activate();

1737 }

1738 Ptr.deref<T>() = Value;

1739 return true;

1740}

1741

1742template <PrimType Name, class T = typename PrimConv::T>

1744 const T &Value = S.Stk.pop<T>();

1747 return false;

1748 if (Ptr.canBeInitialized())

1750 if (const auto *FD = Ptr.getField())

1751 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());

1752 else

1753 Ptr.deref<T>() = Value;

1754 return true;

1755}

1756

1757template <PrimType Name, class T = typename PrimConv::T>

1759 const T &Value = S.Stk.pop<T>();

1762 return false;

1763 if (Ptr.canBeInitialized())

1765 if (const auto *FD = Ptr.getField())

1766 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());

1767 else

1768 Ptr.deref<T>() = Value;

1769 return true;

1770}

1771

1772template <PrimType Name, class T = typename PrimConv::T>

1774 const T &Value = S.Stk.pop<T>();

1777 assert(false);

1778 return false;

1779 }

1780 Ptr.activate();

1781 Ptr.initialize();

1782 new (&Ptr.deref<T>()) T(Value);

1783 return true;

1784}

1785

1786template <PrimType Name, class T = typename PrimConv::T>

1788 const T &Value = S.Stk.pop<T>();

1791 return false;

1793 Ptr.initialize();

1794 new (&Ptr.deref<T>()) T(Value);

1795 return true;

1796}

1797

1798

1799

1800

1801template <PrimType Name, class T = typename PrimConv::T>

1803 const T &Value = S.Stk.pop<T>();

1805

1806 if (Ptr.isUnknownSizeArray())

1807 return false;

1808

1809

1810

1811 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {

1813 new (&Ptr.deref<T>()) T(Value);

1814 return true;

1815 }

1816

1818 if (CheckInit(S, OpPC, ElemPtr))

1819 return false;

1822 return true;

1823}

1824

1825

1826template <PrimType Name, class T = typename PrimConv::T>

1828 const T &Value = S.Stk.pop<T>();

1830 if (Ptr.isUnknownSizeArray())

1831 return false;

1832

1833

1834

1835 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {

1837 new (&Ptr.deref<T>()) T(Value);

1838 return true;

1839 }

1840

1842 if (CheckInit(S, OpPC, ElemPtr))

1843 return false;

1846 return true;

1847}

1848

1852

1854 return false;

1855

1856 return DoMemcpy(S, OpPC, Src, Dest);

1857}

1858

1861 const auto &Base = S.Stk.pop<Pointer>();

1862

1864 return true;

1865}

1866

1869

1870 if (std::optional Ptr = MP.toPointer(S.Ctx)) {

1871 S.Stk.push<Pointer>(*Ptr);

1872 return true;

1873 }

1874 return false;

1875}

1876

1877

1878

1879

1880

1881template <class T, ArithOp Op>

1883 const Pointer &Ptr, bool IsPointerArith = false) {

1884

1885 if (Offset.isZero()) {

1886 S.Stk.push<Pointer>(Ptr);

1887 return true;

1888 }

1889

1891

1892

1894 return false;

1895 }

1896

1897

1899 return false;

1900

1901

1904 uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();

1907 else

1909 return true;

1911 uint64_t O = static_cast<uint64_t>(Offset);

1912 uint64_t N;

1915 else

1917

1918 if (N > 1)

1919 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)

1920 << N << true << 0;

1922 return true;

1923 }

1924

1926

1927 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());

1928 uint64_t Index;

1930 Index = MaxIndex;

1931 else

1933

1935

1936 auto DiagInvalidOffset = [&]() -> void {

1937 const unsigned Bits = Offset.bitWidth();

1938 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);

1939 APSInt APIndex(APInt(Bits + 2, Index, true),

1940 false);

1942 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);

1943 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)

1944 << NewIndex << static_cast<int>(!Ptr.inArray()) << MaxIndex;

1946 };

1947

1949 uint64_t IOffset = static_cast<uint64_t>(Offset);

1950 uint64_t MaxOffset = MaxIndex - Index;

1951

1953

1954 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))

1955 DiagInvalidOffset();

1956

1957

1958 if (Offset.isPositive() && IOffset > MaxOffset)

1959 DiagInvalidOffset();

1960 } else {

1961

1962 if (Offset.isPositive() && Index < IOffset)

1963 DiagInvalidOffset();

1964

1965

1966 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))

1967 DiagInvalidOffset();

1968 }

1969 }

1970

1972 return false;

1973

1974

1975 int64_t WideIndex = static_cast<int64_t>(Index);

1976 int64_t WideOffset = static_cast<int64_t>(Offset);

1979 Result = WideIndex + WideOffset;

1980 else

1981 Result = WideIndex - WideOffset;

1982

1983

1984

1985

1989 return true;

1990 }

1991

1993 return true;

1994}

1995

1996template <PrimType Name, class T = typename PrimConv::T>

1998 const T &Offset = S.Stk.pop<T>();

2000 if (Ptr.isBlockPointer())

2002 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr,

2003 true);

2004}

2005

2006template <PrimType Name, class T = typename PrimConv::T>

2008 const T &Offset = S.Stk.pop<T>();

2010 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr,

2011 true);

2012}

2013

2014template

2018 return false;

2019

2021

2024 return false;

2025

2026

2028

2029

2030 OneT One = OneT::from(1);

2031 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P, true))

2032 return false;

2033

2034

2036 return true;

2037}

2038

2041

2043 return false;

2044

2045 return IncDecPtrHelperArithOp::Add(S, OpPC, Ptr);

2046}

2047

2050

2052 return false;

2053

2054 return IncDecPtrHelperArithOp::Sub(S, OpPC, Ptr);

2055}

2056

2057

2058

2059

2060template <PrimType Name, class T = typename PrimConv::T>

2064

2065 for (const Pointer &P : {LHS, RHS}) {

2066 if (P.isZeroSizeArray()) {

2068 while (auto *AT = dyn_cast(PtrT))

2069 PtrT = AT->getElementType();

2070

2073 S.FFDiag(S.Current->getSource(OpPC),

2074 diag::note_constexpr_pointer_subtraction_zero_size)

2075 << ArrayTy;

2076

2077 return false;

2078 }

2079 }

2080

2081 if (RHS.isZero()) {

2082 S.Stk.push<T>(T::from(LHS.getIndex()));

2083 return true;

2084 }

2085

2087

2088 return false;

2089 }

2090

2091 if (LHS.isZero() && RHS.isZero()) {

2092 S.Stk.push<T>();

2093 return true;

2094 }

2095

2100 T B = RHS.isBlockPointer()

2101 ? (RHS.isElementPastEnd() ? T::from(RHS.getNumElems())

2102 : T::from(RHS.getIndex()))

2103 : T::from(RHS.getIntegerRepresentation());

2104

2105 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);

2106}

2107

2108

2109

2110

2111

2113 S.Current->destroy(I);

2114 return true;

2115}

2116

2118 S.Current->initScope(I);

2119 return true;

2120}

2121

2122

2123

2124

2125

2129 S.Stk.push<U>(U::from(S.Stk.pop<T>()));

2130 return true;

2131}

2132

2133

2134

2136 llvm::RoundingMode RM) {

2140 return true;

2141}

2142

2145 FixedPointSemantics::getFromOpaqueInt(FPS);

2146 const auto &Source = S.Stk.pop<FixedPoint>();

2147

2148 bool Overflow;

2149 FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);

2150

2152 return false;

2153

2155 return true;

2156}

2157

2158

2159

2160template <PrimType Name, class T = typename PrimConv::T>

2164 return true;

2165}

2166

2167template <PrimType Name, class T = typename PrimConv::T>

2171 return true;

2172}

2173

2174template <PrimType Name, class T = typename PrimConv::T>

2176 const llvm::fltSemantics *Sem, uint32_t FPOI) {

2177 const T &From = S.Stk.pop<T>();

2178 APSInt FromAP = From.toAPSInt();

2180

2182 auto Status =

2185

2187}

2188

2189template <PrimType Name, class T = typename PrimConv::T>

2192

2193 if constexpr (std::is_same_v<T, Boolean>) {

2195 return true;

2196 } else {

2198 !T::isSigned());

2200

2201

2202 if ((Status & APFloat::opStatus::opInvalidOp)) {

2203 const Expr *E = S.Current->getExpr(OpPC);

2205

2206 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;

2207 if (S.noteUndefinedBehavior()) {

2209 return true;

2210 }

2211 return false;

2212 }

2213

2217 }

2218}

2219

2221 uint32_t BitWidth, uint32_t FPOI) {

2223

2224 APSInt Result(BitWidth, true);

2226

2227

2228 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())

2230

2234}

2235

2237 uint32_t BitWidth, uint32_t FPOI) {

2239

2240 APSInt Result(BitWidth, false);

2242

2243

2244 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())

2246

2250}

2251

2253 const Pointer &Ptr, unsigned BitWidth);

2256

2257template <PrimType Name, class T = typename PrimConv::T>

2260

2262 return false;

2263

2265 return true;

2266}

2267

2268template <PrimType Name, class T = typename PrimConv::T>

2270 uint32_t FPS) {

2271 const T &Int = S.Stk.pop<T>();

2272

2274

2275 bool Overflow;

2277

2279 return false;

2280

2282 return true;

2283}

2284

2286 uint32_t FPS) {

2288

2290

2291 bool Overflow;

2293

2295 return false;

2296

2298 return true;

2299}

2300

2302 const llvm::fltSemantics *Sem) {

2303 const auto &Fixed = S.Stk.pop<FixedPoint>();

2304

2305 S.Stk.push<Floating>(Fixed.toFloat(Sem));

2306 return true;

2307}

2308

2309template <PrimType Name, class T = typename PrimConv::T>

2311 const auto &Fixed = S.Stk.pop<FixedPoint>();

2312

2313 bool Overflow;

2314 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);

2315

2317 return false;

2318

2319 S.Stk.push<T>(Int);

2320 return true;

2321}

2322

2324 const auto &Ptr = S.Stk.peek<Pointer>();

2325

2326 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {

2327 bool HasValidResult = !Ptr.isZero();

2328

2329 if (HasValidResult) {

2330

2331 } else if (!S.getLangOpts().CPlusPlus26) {

2332 const SourceInfo &E = S.Current->getSource(OpPC);

2333 S.CCEDiag(E, diag::note_constexpr_invalid_cast)

2334 << 3 << "'void *'" << S.Current->getRange(OpPC);

2335 }

2336 } else {

2337 const SourceInfo &E = S.Current->getSource(OpPC);

2338 S.CCEDiag(E, diag::note_constexpr_invalid_cast)

2339 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);

2340 }

2341

2342 return true;

2343}

2344

2345

2346

2347

2348

2349template <PrimType Name, class T = typename PrimConv::T>

2351 S.Stk.push<T>(T::zero());

2352 return true;

2353}

2354

2357 return true;

2358}

2359

2362 return true;

2363}

2364

2365template <PrimType Name, class T = typename PrimConv::T>

2368

2369

2370 S.Stk.push<T>(Value, Desc);

2371 return true;

2372}

2373

2374template <PrimType Name, class T = typename PrimConv::T>

2376 const auto &P = S.Stk.pop<T>();

2377 if (P.isWeak())

2378 return false;

2380 return true;

2381}

2382

2383

2384

2385

2386

2388

2389 if (S.checkingPotentialConstantExpression()) {

2390 return false;

2391 }

2392

2393 const Pointer &This = S.Current->getThis();

2395 return false;

2396

2397

2398 if (This.isDummy()) {

2399 assert(isa(S.Current->getFunction()->getDecl()));

2400 assert(This.getRecord());

2401 assert(

2402 This.getRecord()->getDecl() ==

2403 cast(S.Current->getFunction()->getDecl())->getParent());

2404 }

2405

2407 return true;

2408}

2409

2411 assert(S.Current->getFunction()->hasRVO());

2412 if (S.checkingPotentialConstantExpression())

2413 return false;

2414 S.Stk.push<Pointer>(S.Current->getRVOPtr());

2415 return true;

2416}

2417

2418

2419

2420

2421

2422template <class LT, class RT, ShiftDir Dir>

2424 const unsigned Bits = LHS.bitWidth();

2425

2426

2428 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),

2429 RHS.bitWidth(), &RHS);

2430

2431 if (RHS.isNegative()) {

2432

2433

2434 const SourceInfo &Loc = S.Current->getSource(OpPC);

2435 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();

2436 if (!S.noteUndefinedBehavior())

2437 return false;

2438 RHS = -RHS;

2441 S, OpPC, LHS, RHS);

2442 }

2443

2444 if (!CheckShift(S, OpPC, LHS, RHS, Bits))

2445 return false;

2446

2447

2448

2449

2450

2451

2452

2453 typename LT::AsUnsigned R;

2454 unsigned MaxShiftAmount = LHS.bitWidth() - 1;

2456 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==

2458 if (LHS.isNegative())

2459 R = LT::AsUnsigned::zero(LHS.bitWidth());

2460 else {

2461 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());

2462 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),

2463 LT::AsUnsigned::from(RHS, Bits), Bits, &R);

2464 }

2465 } else if (LHS.isNegative()) {

2466 if (LHS.isMin()) {

2467 R = LT::AsUnsigned::zero(LHS.bitWidth());

2468 } else {

2469

2470 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);

2471 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,

2472 &R);

2473 R = -R;

2474 }

2475 } else {

2476

2477 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),

2478 LT::AsUnsigned::from(RHS, Bits), Bits, &R);

2479 }

2480 } else {

2481

2482 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==

2484 R = LT::AsUnsigned::from(-1);

2485 } else {

2486

2487 LT A;

2488 LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);

2489 R = LT::AsUnsigned::from(A);

2490 }

2491 }

2492

2493 S.Stk.push<LT>(LT::from(R));

2494 return true;

2495}

2496

2497template <PrimType NameL, PrimType NameR>

2501 auto RHS = S.Stk.pop();

2502 auto LHS = S.Stk.pop<LT>();

2503

2504 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);

2505}

2506

2507template <PrimType NameL, PrimType NameR>

2511 auto RHS = S.Stk.pop();

2512 auto LHS = S.Stk.pop<LT>();

2513

2514 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);

2515}

2516

2518 const auto &RHS = S.Stk.pop<FixedPoint>();

2519 const auto &LHS = S.Stk.pop<FixedPoint>();

2520 llvm::FixedPointSemantics LHSSema = LHS.getSemantics();

2521

2522 unsigned ShiftBitWidth =

2523 LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;

2524

2525

2526

2527

2528 if (RHS.isNegative()) {

2529 S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)

2530 << RHS.toAPSInt();

2531 } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(

2532 ShiftBitWidth)) != RHS.toAPSInt()) {

2533 const Expr *E = S.Current->getExpr(OpPC);

2534 S.CCEDiag(E, diag::note_constexpr_large_shift)

2535 << RHS.toAPSInt() << E->getType() << ShiftBitWidth;

2536 }

2537

2542 return false;

2543 } else {

2546 return false;

2547 }

2548

2550 return true;

2551}

2552

2553

2554

2555

2556

2558 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();

2559 S.FFDiag(EndLoc, diag::note_constexpr_no_return);

2560 return false;

2561}

2562

2563

2564

2565

2566

2570 return true;

2571}

2572

2576 return true;

2577}

2578

2579

2580

2581

2582

2583

2584

2585

2586

2587template <PrimType Name, class T = typename PrimConv::T>

2589 const T &Offset = S.Stk.pop<T>();

2591

2592 if (!Ptr.isZero() && !Offset.isZero()) {

2594 return false;

2595 }

2596

2597 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))

2598 return false;

2599

2601}

2602

2603template <PrimType Name, class T = typename PrimConv::T>

2605 const T &Offset = S.Stk.pop<T>();

2607

2608 if (!Ptr.isZero() && !Offset.isZero()) {

2610 return false;

2611 }

2612

2613 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))

2614 return false;

2615

2617}

2618

2619template <PrimType Name, class T = typename PrimConv::T>

2622

2624 return false;

2625

2628 return true;

2629}

2630

2631template <PrimType Name, class T = typename PrimConv::T>

2634

2636 return false;

2637

2640 return true;

2641}

2642

2643template <PrimType Name, class T = typename PrimConv::T>

2645 uint32_t DestIndex, uint32_t Size) {

2646 const auto &SrcPtr = S.Stk.pop<Pointer>();

2647 const auto &DestPtr = S.Stk.peek<Pointer>();

2648

2649 for (uint32_t I = 0; I != Size; ++I) {

2651

2653 return false;

2654

2658 }

2659 return true;

2660}

2661

2662

2663

2666

2668 S.Stk.push<Pointer>(Ptr);

2669 return true;

2670 }

2671

2673 return false;

2674

2677 return true;

2678 }

2679

2680 const SourceInfo &E = S.Current->getSource(OpPC);

2681 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);

2682

2683 return false;

2684}

2685

2687 assert(Func);

2689 return true;

2690}

2691

2692template <PrimType Name, class T = typename PrimConv::T>

2694 const T &IntVal = S.Stk.pop<T>();

2695

2696 if (Desc)

2697 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)

2699

2700 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);

2701 return true;

2702}

2703

2706 return true;

2707}

2708

2711

2712 S.Stk.push<Pointer>(MP.getBase());

2713 return true;

2714}

2715

2718

2719 const auto *FD = cast(MP.getDecl());

2720 const auto *Func = S.getContext().getOrCreateFunction(FD);

2721

2723 return true;

2724}

2725

2726

2727

2730 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)

2731 << S.Current->getRange(OpPC);

2732 return false;

2733}

2734

2737 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)

2738 << S.Current->getRange(OpPC);

2739 return false;

2740}

2741

2742

2745 return S.noteSideEffect();

2746}

2747

2748

2750 bool Fatal) {

2752

2753

2755 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)

2756 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);

2757 return !Fatal;

2758 }

2759 return false;

2760}

2761

2764 assert(DR);

2765

2767 const SourceInfo &Loc = S.Current->getSource(OpPC);

2768 const auto *VD = cast(DR->getDecl());

2769 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;

2770 S.Note(VD->getLocation(), diag::note_declared_at);

2771 return false;

2772 }

2773

2775}

2776

2778 if (S.inConstantContext()) {

2779 const SourceRange &ArgRange = S.Current->getRange(OpPC);

2780 const Expr *E = S.Current->getExpr(OpPC);

2781 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;

2782 }

2783 return false;

2784}

2785

2787 const auto Val = S.Stk.pop<Boolean>();

2788

2789 if (Val)

2790 return true;

2791

2792

2794 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);

2795 return false;

2796}

2797

2798template <PrimType Name, class T = typename PrimConv::T>

2801 for (size_t I = 0; I != E->getNumExpressions(); ++I)

2802 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());

2803

2806 return false;

2807

2808 S.Stk.push<T>(T::from(Result));

2809

2810 return true;

2811}

2812

2813template <PrimType Name, class T = typename PrimConv::T>

2815 const T &Arg = S.Stk.peek<T>();

2816 if (!Arg.isZero())

2817 return true;

2818

2820 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);

2821

2822 return false;

2823}

2824

2827

2828template <PrimType Name, class T = typename PrimConv::T>

2830 assert(ED);

2832 const APSInt Val = S.Stk.peek<T>().toAPSInt();

2833

2834 if (S.inConstantContext())

2836 return true;

2837}

2838

2839

2840template <PrimType TIn, PrimType TOut>

2845

2846 const FromT &OldPtr = S.Stk.pop();

2847

2848 if constexpr (std::is_same_v<FromT, FunctionPointer> &&

2849 std::is_same_v<ToT, Pointer>) {

2850 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());

2851 return true;

2852 } else if constexpr (std::is_same_v<FromT, Pointer> &&

2853 std::is_same_v<ToT, FunctionPointer>) {

2854 if (OldPtr.isFunctionPointer()) {

2855 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),

2856 OldPtr.getByteOffset());

2857 return true;

2858 }

2859 }

2860

2861 S.Stk.push(ToT(OldPtr.getIntegerRepresentation(), nullptr));

2862 return true;

2863}

2864

2866

2867

2868

2869

2871 VD->isStaticLocal());

2872

2873 if (VD == S.EvaluatingDecl)

2874 return true;

2875

2877 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)

2879 return false;

2880 }

2881 return true;

2882}

2883

2885 assert(Desc);

2886

2888 return false;

2889

2891 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),

2893 assert(B);

2894

2896

2897 return true;

2898}

2899

2900template <PrimType Name, class SizeT = typename PrimConv::T>

2902 bool IsNoThrow) {

2904 return false;

2905

2906 SizeT NumElements = S.Stk.pop();

2908 if (!IsNoThrow)

2909 return false;

2910

2911

2912 S.Stk.push<Pointer>(0, nullptr);

2913 return true;

2914 }

2915

2918 Allocator.allocate(Source, T, static_cast<size_t>(NumElements),

2920 assert(B);

2922

2923 return true;

2924}

2925

2926template <PrimType Name, class SizeT = typename PrimConv::T>

2928 bool IsNoThrow) {

2930 return false;

2931

2932 SizeT NumElements = S.Stk.pop();

2934 IsNoThrow)) {

2935 if (!IsNoThrow)

2936 return false;

2937

2938

2939 S.Stk.push<Pointer>(0, ElementDesc);

2940 return true;

2941 }

2942

2945 Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),

2947 assert(B);

2948

2950

2951 return true;

2952}

2953

2954bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,

2955 bool IsGlobalDelete);

2956

2959 return true;

2960}

2961

2963 return S.maybeDiagnoseDanglingAllocations();

2964}

2965

2966

2967

2969 std::optional<uint64_t> ArraySize = std::nullopt);

2970

2971template <PrimType Name, class T = typename PrimConv::T>

2973 const auto &Size = S.Stk.pop<T>();

2975}

2977

2978template <PrimType Name, class T = typename PrimConv::T>

2980 uint32_t ResultBitWidth,

2981 const llvm::fltSemantics *Sem) {

2983

2984 if (CheckLoad(S, OpPC, FromPtr))

2985 return false;

2986

2987 if constexpr (std::is_same_v<T, Pointer>) {

2988

2990 return true;

2991 } else {

2992

2993 size_t BuffSize = ResultBitWidth / 8;

2995 bool HasIndeterminateBits = false;

2996

2997 Bits FullBitWidth(ResultBitWidth);

2998 Bits BitWidth = FullBitWidth;

2999

3000 if constexpr (std::is_same_v<T, Floating>) {

3001 assert(Sem);

3002 BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));

3003 }

3004

3005 if (DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,

3006 HasIndeterminateBits))

3007 return false;

3008

3009 if (CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))

3010 return false;

3011

3012 if constexpr (std::is_same_v<T, Floating>) {

3013 assert(Sem);

3014 S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));

3015 } else {

3016 assert(!Sem);

3017 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));

3018 }

3019 return true;

3020 }

3021}

3022

3026

3027 if (CheckLoad(S, OpPC, FromPtr))

3028 return false;

3029

3031 return false;

3032

3033 return true;

3034}

3035

3036

3037bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,

3038 const Type *TypeInfoType);

3039bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);

3040bool DiagTypeid(InterpState &S, CodePtr OpPC);

3041

3042

3043

3044

3045

3047 if constexpr (std::is_pointer::value) {

3048 uint32_t ID = OpPC.read<uint32_t>();

3049 return reinterpret_cast<T>(S.P.getNativePointer(ID));

3050 } else {

3051 return OpPC.read<T>();

3052 }

3053}

3054

3058 return F;

3059}

3060

3061template <>

3062inline IntegralAP ReadArg<IntegralAP>(InterpState &S,

3063 CodePtr &OpPC) {

3065 OpPC += align(I.bytesToSerialize());

3066 return I;

3067}

3068

3069template <>

3070inline IntegralAP ReadArg<IntegralAP>(InterpState &S,

3071 CodePtr &OpPC) {

3073 OpPC += align(I.bytesToSerialize());

3074 return I;

3075}

3076

3077template <>

3081 return FP;

3082}

3083

3084}

3085}

3086

3087#endif

Defines the clang::ASTContext interface.

ASTImporterLookupTable & LT

void HandleComplexComplexDiv(APFloat A, APFloat B, APFloat C, APFloat D, APFloat &ResR, APFloat &ResI)

void HandleComplexComplexMul(APFloat A, APFloat B, APFloat C, APFloat D, APFloat &ResR, APFloat &ResI)

static std::string toString(const clang::SanitizerSet &Sanitizers)

Produce a string containing comma-separated names of sanitizers in Sanitizers set.

APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...

QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const

Return the unique reference to the type for a constant array of the specified element type.

Represents a static or instance method of a struct/union/class.

CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).

const ValueInfo * getValueInfo(ComparisonCategoryResult ValueKind) const

ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const

Converts the specified result kind into the correct result kind for this category.

static unsigned getMaxSizeBits(const ASTContext &Context)

Determine the maximum number of active bits that an array's size can require, which limits the maximu...

A reference to a declared variable, function, enum, etc.

Decl - This represents one declaration (or definition), e.g.

SourceLocation getLocation() const

bool isFixed() const

Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...

This represents one expression.

SourceLocation getExprLoc() const LLVM_READONLY

getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...

static FPOptions getFromOpaqueInt(storage_type Value)

RoundingMode getRoundingMode() const

Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...

APValue * getOrCreateValue(bool MayCreate) const

Get the storage for the constant value of a materialized temporary of static storage duration.

Expr * getTemporaryExpr()

Retrieve the expression to which the temporary materialization conversion was applied.

OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...

A (possibly-)qualified type.

Represents a struct/union/class.

ASTContext & getASTContext() const

const LangOptions & getLangOpts() const

Encodes a location in the source.

A trivial tuple used to represent a source range.

SourceRange getSourceRange() const LLVM_READONLY

SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...

The base class of the type hierarchy.

Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...

Represents a variable declaration or definition.

bool isStaticLocal() const

Returns true if a variable with function scope is a static local variable.

ThreadStorageClassSpecifier getTSCSpec() const

bool isLocalVarDecl() const

Returns true for local variable declarations other than parameters.

bool isUsableInConstantExpressions(const ASTContext &C) const

Determine whether this variable's value can be used in a constant expression, according to the releva...

A memory block, either on the stack or in the heap.

Wrapper around boolean types.

static Boolean from(T Value)

Pointer into the code segment.

std::enable_if_t<!std::is_pointer< T >::value, T > read()

Reads data and advances the pointer.

Manages dynamic memory allocations done during bytecode interpretation.

Wrapper around fixed point types.

llvm::FixedPointSemantics getSemantics() const

static bool shiftRight(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)

static FixedPoint deserialize(const std::byte *Buff)

static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)

static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, bool *Overflow)

size_t bytesToSerialize() const

static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)

static Floating deserialize(const std::byte *Buff)

static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)

const APFloat & getAPFloat() const

static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)

static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating &Result)

Floating toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM) const

size_t bytesToSerialize() const

static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)

static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)

static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)

APFloat::opStatus convertToInteger(APSInt &Result) const

const Function * getFunction() const

ComparisonCategoryResult compare(const FunctionPointer &RHS) const

std::string toDiagnosticString(const ASTContext &Ctx) const

static IntegralAP< Signed > deserialize(const std::byte *Buff)

static IntegralAP zero(int32_t BitWidth)

static IntegralAP from(T Value, unsigned NumBits=0)

Wrapper around numeric types.

Frame storing local variables.

ComparisonCategoryResult compare(const MemberPointer &RHS) const

A pointer to a memory block, live or dead.

static bool hasSameBase(const Pointer &A, const Pointer &B)

Checks if two pointers are comparable.

Pointer narrow() const

Restricts the scope of an array element pointer.

void deactivate() const

Deactivates an entire strurcutre.

bool isInitialized() const

Checks if an object was initialized.

Pointer atIndex(uint64_t Idx) const

Offsets a pointer inside an array.

bool isDummy() const

Checks if the pointer points to a dummy value.

Pointer atFieldSub(unsigned Off) const

Subtract the given offset from the current Base and Offset of the pointer.

bool isExtern() const

Checks if the storage is extern.

int64_t getIndex() const

Returns the index into an array.

Pointer atField(unsigned Off) const

Creates a pointer to a field.

T & deref() const

Dereferences the pointer, if it's live.

unsigned getNumElems() const

Returns the number of elements.

bool isUnknownSizeArray() const

Checks if the structure is an array of unknown size.

void activate() const

Activats a field.

bool isIntegralPointer() const

bool isArrayRoot() const

Whether this array refers to an array, but not to the first element.

bool inArray() const

Checks if the innermost field is an array.

uint64_t getByteOffset() const

Returns the byte offset from the start.

std::string toDiagnosticString(const ASTContext &Ctx) const

Converts the pointer to a string usable in diagnostics.

bool isZero() const

Checks if the pointer is null.

ComparisonCategoryResult compare(const Pointer &Other) const

Compare two pointers.

const IntPointer & asIntPointer() const

bool isRoot() const

Pointer points directly to a block.

const Descriptor * getDeclDesc() const

Accessor for information about the declaration site.

unsigned getOffset() const

Returns the offset into an array.

bool isOnePastEnd() const

Checks if the index is one past end.

uint64_t getIntegerRepresentation() const

Pointer expand() const

Expands a pointer to the containing array, undoing narrowing.

bool isElementPastEnd() const

Checks if the pointer is an out-of-bounds element pointer.

bool isBlockPointer() const

const FunctionPointer & asFunctionPointer() const

bool isFunctionPointer() const

const Descriptor * getFieldDesc() const

Accessors for information about the innermost field.

size_t elemSize() const

Returns the element size of the innermost field.

bool canBeInitialized() const

If this pointer has an InlineDescriptor we can use to initialize.

const BlockPointer & asBlockPointer() const

void initialize() const

Initializes a field.

Describes the statement/declaration an opcode was generated from.

static bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left)

bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)

bool InitPop(InterpState &S, CodePtr OpPC)

bool Shr(InterpState &S, CodePtr OpPC)

bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, const LifetimeExtendedTemporaryDecl *Temp)

  1. Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initializes ...

bool IncPop(InterpState &S, CodePtr OpPC)

  1. Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...

bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)

bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)

bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)

bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)

bool GT(InterpState &S, CodePtr OpPC)

bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)

bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Checks if a value can be initialized.

static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)

bool GetMemberPtrBase(InterpState &S, CodePtr OpPC)

bool DecPop(InterpState &S, CodePtr OpPC)

  1. Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...

bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)

bool NarrowPtr(InterpState &S, CodePtr OpPC)

bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off)

bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)

Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)

bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool SideEffect(InterpState &S, CodePtr OpPC)

static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)

bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)

bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType)

bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)

The same as InitElem, but pops the pointer as well.

bool StoreBitField(InterpState &S, CodePtr OpPC)

bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Offset)

Checks if the dowcast using the given offset is possible with the given pointer.

bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, DynamicAllocator::Form AllocForm, DynamicAllocator::Form DeleteForm, const Descriptor *D, const Expr *NewExpr)

Diagnose mismatched new[]/delete or new/delete[] pairs.

bool BitCast(InterpState &S, CodePtr OpPC)

bool LoadPop(InterpState &S, CodePtr OpPC)

bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Descriptor *Desc)

static llvm::RoundingMode getRoundingMode(FPOptions FPO)

static bool IncPtr(InterpState &S, CodePtr OpPC)

bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)

We aleady know the given DeclRefExpr is invalid for some reason, now figure out why and print appropr...

bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, const Type *TypeInfoType)

Typeid support.

bool Dup(InterpState &S, CodePtr OpPC)

bool CheckCallDepth(InterpState &S, CodePtr OpPC)

Checks if calling the currently active function would exceed the allowed call depth.

bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)

Checks the 'this' pointer.

bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)

bool CheckNonNullArg(InterpState &S, CodePtr OpPC)

bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, llvm::ArrayRef< int64_t > ArrayIndices, int64_t &Result)

Interpret an offsetof operation.

bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, const APSInt &IntValue)

Sets the given integral value to the pointer, which is of a std::{weak,partial,strong}_ordering type.

static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)

bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS)

Checks if Div/Rem operation on LHS and RHS is valid.

bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)

Checks if the Descriptor is of a constexpr or const global variable.

bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD)

bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)

bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)

bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)

  1. Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack

bool Div(InterpState &S, CodePtr OpPC)

  1. Pops the RHS from the stack.

bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Checks if a pointer points to a mutable field.

bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)

bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)

Same as GetGlobal, but without the checks.

bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)

bool SubPtr(InterpState &S, CodePtr OpPC)

  1. Pops a Pointer from the stack.

bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)

Checks if Ptr is a one-past-the-end pointer.

bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)

bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)

bool Mulc(InterpState &S, CodePtr OpPC)

bool RetVoid(InterpState &S, CodePtr &PC)

bool ArrayElemPtr(InterpState &S, CodePtr OpPC)

bool NE(InterpState &S, CodePtr OpPC)

bool NoRet(InterpState &S, CodePtr OpPC)

bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)

bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)

Checks if a value can be loaded from a block.

static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)

bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, uint32_t ResultBitWidth, const llvm::fltSemantics *Sem)

bool Shl(InterpState &S, CodePtr OpPC)

bool RVOPtr(InterpState &S, CodePtr OpPC)

llvm::FixedPointSemantics FixedPointSemantics

bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)

bool CastPointerIntegral(InterpState &S, CodePtr OpPC)

constexpr bool isPtrType(PrimType T)

bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr, bool IsPointerArith=false)

bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool SubOffset(InterpState &S, CodePtr OpPC)

constexpr size_t align(size_t Size)

Aligns a size to the pointer alignment.

bool BitXor(InterpState &S, CodePtr OpPC)

  1. Pops the RHS from the stack.

bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)

Checks if a pointer is in range.

bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)

bool ExpandPtr(InterpState &S, CodePtr OpPC)

bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)

Checks if a method is pure virtual.

bool Store(InterpState &S, CodePtr OpPC)

bool Divc(InterpState &S, CodePtr OpPC)

bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr)

bool GetField(InterpState &S, CodePtr OpPC, uint32_t I)

  1. Peeks a pointer on the stack 2) Pushes the value of the pointer's field on the stack

bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)

bool This(InterpState &S, CodePtr OpPC)

bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I)

bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)

Checks if dynamic memory allocation is available in the current language mode.

bool InitField(InterpState &S, CodePtr OpPC, uint32_t I)

  1. Pops the value from the stack 2) Peeks a pointer from the stack 3) Pushes the value to field I of ...

bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)

llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn

T ReadArg(InterpState &S, CodePtr &OpPC)

bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)

Checks if a pointer is live and accessible.

bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool ArrayDecay(InterpState &S, CodePtr OpPC)

Just takes a pointer and checks if it's an incomplete array type.

bool DiagTypeid(InterpState &S, CodePtr OpPC)

bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

This is not used by any of the opcodes directly.

bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, const LifetimeExtendedTemporaryDecl *Temp)

  1. Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initialized ...

bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte)

bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)

bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)

bool BitAnd(InterpState &S, CodePtr OpPC)

  1. Pops the RHS from the stack.

bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)

Checks if the shift operation is legal.

static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)

FixedPoint ReadArg< FixedPoint >(InterpState &S, CodePtr &OpPC)

static bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)

void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)

bool LE(InterpState &S, CodePtr OpPC)

PrimType

Enumeration of the primitive types of the VM.

bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E)

bool Zero(InterpState &S, CodePtr OpPC)

bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)

bool Unsupported(InterpState &S, CodePtr OpPC)

bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)

bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Checks if a value can be stored in a block.

bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)

Checks if a pointer is null.

bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, const Pointer &Ptr)

Check the source of the pointer passed to delete/delete[] has actually been heap allocated by us.

bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status, FPOptions FPO)

Checks if the result of a floating-point operation is valid in the current context.

bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)

  1. Pops a Floating from the stack.

ComparisonCategoryResult Compare(const T &X, const T &Y)

Helper to compare two comparable types.

bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)

bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)

bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)

static bool DecPtr(InterpState &S, CodePtr OpPC)

static bool CheckAllocations(InterpState &S, CodePtr OpPC)

bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)

bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)

bool ToMemberPtr(InterpState &S, CodePtr OpPC)

static bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)

bool Rem(InterpState &S, CodePtr OpPC)

  1. Pops the RHS from the stack.

bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)

bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, std::optional< uint64_t > ArraySize)

Check if the initializer and storage types of a placement-new expression match.

bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D)

bool Dump(InterpState &S, CodePtr OpPC)

bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)

static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)

bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)

bool IsNonNull(InterpState &S, CodePtr OpPC)

bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)

bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)

bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Checks if the array is offsetable.

bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Check if a global variable is initialized.

bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)

bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)

Checks if all the arguments annotated as 'nonnull' are in fact not null.

bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)

bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)

bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)

Checks if a pointer is a dummy pointer.

bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)

bool CmpHelper< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)

Function pointers cannot be compared in an ordered way.

bool Comp(InterpState &S, CodePtr OpPC)

  1. Pops the value from the stack.

static bool CastFixedPointFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem)

bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool DecayPtr(InterpState &S, CodePtr OpPC)

OldPtr -> Integer -> NewPtr.

bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)

bool StorePop(InterpState &S, CodePtr OpPC)

void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func)

bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)

  1. Pops the value from the stack.

bool FinishInit(InterpState &S, CodePtr OpPC)

static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)

bool Mul(InterpState &S, CodePtr OpPC)

bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS)

bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx)

  1. Pops the value from the stack 2) Peeks a pointer and gets its index \Idx 3) Sets the value on the ...

bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)

bool Pop(InterpState &S, CodePtr OpPC)

size_t primSize(PrimType Type)

Returns the size of a primitive type in bytes.

bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)

bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func, const CallExpr *CE, uint32_t BuiltinID)

bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)

bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call, uint32_t BuiltinID)

Interpret a builtin function.

bool FinishInitPop(InterpState &S, CodePtr OpPC)

bool InRange(InterpState &S, CodePtr OpPC)

bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)

bool Neg(InterpState &S, CodePtr OpPC)

bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Checks if the variable has externally defined storage.

bool BitOr(InterpState &S, CodePtr OpPC)

  1. Pops the RHS from the stack.

bool Inv(InterpState &S, CodePtr OpPC)

bool Load(InterpState &S, CodePtr OpPC)

bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)

bool Cast(InterpState &S, CodePtr OpPC)

bool EQ(InterpState &S, CodePtr OpPC)

bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I)

  1. Pops a pointer from the stack 2) Pushes the value of the pointer's field on the stack

bool CmpHelperEQ< MemberPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)

bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)

Checks if a method can be called.

bool AddOffset(InterpState &S, CodePtr OpPC)

bool Const(InterpState &S, CodePtr OpPC, const T &Arg)

bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)

Copy the contents of Src into Dest.

bool Memcpy(InterpState &S, CodePtr OpPC)

bool GE(InterpState &S, CodePtr OpPC)

bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, bool &HasIndeterminateBits)

bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, unsigned ElemSize, bool IsNoThrow)

bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)

bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)

static bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC)

constexpr bool isIntegralType(PrimType T)

bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)

bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, uint32_t FPOI)

bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)

bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Checks if a pointer points to const storage.

bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)

bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)

bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)

bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)

bool Interpret(InterpState &S)

Interpreter entry point.

bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)

bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)

bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)

Same here, but only for casts.

bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)

bool Ret(InterpState &S, CodePtr &PC)

bool Flip(InterpState &S, CodePtr OpPC)

[Value1, Value2] -> [Value2, Value1]

bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)

bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)

Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need to know what bitwidth the resu...

bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)

bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI)

bool Assume(InterpState &S, CodePtr OpPC)

bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Checks if a method can be invoked on an object.

bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)

bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t FPOI)

static bool IsConstantContext(InterpState &S, CodePtr OpPC)

bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)

bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)

The JSON file list parser is used to communicate input to InstallAPI.

ComparisonCategoryResult

An enumeration representing the possible results of a three-way comparison.

CheckSubobjectKind

The order of this enum is important for diagnostics.

@ Result

The result type of a method or function.

AccessKinds

Kinds of access we can perform on an object, for diagnostics.

const FunctionProtoType * T

unsigned Base

Start of the current subfield.

Block * Pointee

The block the pointer is pointing to.

Describes a memory block created by an allocation site.

unsigned getSize() const

Returns the size of the object without metadata.

static constexpr unsigned MaxArrayElemBytes

Maximum number of bytes to be used for array elements.

PrimType getPrimType() const

const Expr * asExpr() const

Inline descriptor embedded in structures and arrays.

IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const

Mapping from primitive types to their representation.