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

1

2

3

4

5

6

7

8

25#include "llvm/ADT/StringExtras.h"

26

27using namespace clang;

29

31 llvm::report_fatal_error("Interpreter cannot return values");

32}

33

34

35

36

37

39 PC += Offset;

40 return true;

41}

42

44 if (S.Stk.pop<bool>()) {

45 PC += Offset;

46 }

47 return true;

48}

49

51 if (!S.Stk.pop<bool>()) {

52 PC += Offset;

53 }

54 return true;

55}

56

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

60 S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;

62}

63

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

69

70 if (isa(D)) {

72 S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;

74 } else {

75 S.FFDiag(E);

76 }

77 return false;

78 }

79

80 if (D->getType().isConstQualified()) {

82 } else if (const auto *VD = dyn_cast(D)) {

83 if (!VD->getAnyInitializer()) {

85 } else {

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

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

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

89 }

90 }

91

92 return false;

93}

94

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

99 S.FFDiag(Loc);

100 return;

101 }

102

103 if (const auto *VarD = dyn_cast(VD);

104 VarD && VarD->getType().isConstQualified() &&

105 !VarD->getAnyInitializer()) {

107 return;

108 }

109

110

111

112 if (isa(VD))

113 return;

114

116 S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;

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

118 return;

119 }

120

121 S.FFDiag(Loc,

122 S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr

123 : diag::note_constexpr_ltor_non_integral,

124 1)

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

127}

128

132 return true;

133

136

139 while (U.isRoot() && U.inUnion() && U.isActive()) {

140 if (U.getField())

141 C = U;

142 U = U.getBase();

143 }

144 assert(C.isField());

145

146

147 const FieldDecl *InactiveField = C.getField();

148 assert(InactiveField);

149

150

151

152

153

154

155

156

157

158

159

160

161

162 if (U.getFieldDesc()->isUnion())

163 return true;

164

165

166 const Record *R = U.getRecord();

167 assert(R && R->isUnion() && "Not a union");

168

169 const FieldDecl *ActiveField = nullptr;

170 for (const Record::Field &F : R->fields()) {

171 const Pointer &Field = U.atField(F.Offset);

172 if (Field.isActive()) {

173 ActiveField = Field.getField();

174 break;

175 }

176 }

177

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

179 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)

180 << AK << InactiveField << !ActiveField << ActiveField;

181 return false;

182}

183

188 return true;

189

190 const auto *MTE = dyn_cast_if_present(

192 if (!MTE)

193 return true;

194

195

196

197

198 if (!MTE->isUsableInConstantExpressions(S.getASTContext()) &&

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

201 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;

202 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);

203 return false;

204 }

205 }

206 return true;

207}

208

212 return true;

213

214 if (S.P.getCurrentDecl() == ID)

215 return true;

216

217 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);

218 return false;

219 }

220 return true;

221}

222

224namespace interp {

226 PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);

228}

229

232 assert(S.Current);

233 assert(Func);

234

235 if (Func->isUnevaluatedBuiltin())

236 return;

237

238

239

240 if (unsigned BID = Func->getBuiltinID();

242 const auto *CE =

243 cast(S.Current->Caller->getExpr(S.Current->getRetPC()));

244 for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {

245 const Expr *A = CE->getArg(I);

247 }

248 return;

249 }

250

251 if (S.Current->Caller && Func->isVariadic()) {

252

253

254

255 unsigned NumVarArgs;

256 const Expr *const *Args = nullptr;

257 unsigned NumArgs = 0;

258 const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());

259 if (const auto *CE = dyn_cast(CallSite)) {

260 Args = CE->getArgs();

261 NumArgs = CE->getNumArgs();

262 } else if (const auto *CE = dyn_cast(CallSite)) {

263 Args = CE->getArgs();

264 NumArgs = CE->getNumArgs();

265 } else

266 assert(false && "Can't get arguments from that expression type");

267

268 assert(NumArgs >= Func->getNumWrittenParams());

269 NumVarArgs = NumArgs - (Func->getNumWrittenParams() +

270 isa(CallSite));

271 for (unsigned I = 0; I != NumVarArgs; ++I) {

272 const Expr *A = Args[NumArgs - 1 - I];

274 }

275 }

276

277

278

281}

282

285 return true;

286

289 return true;

290

291 if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {

294 }

295 return false;

296}

297

300 return true;

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

302 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);

303 return false;

304}

305

309 const auto &Src = S.Current->getSource(OpPC);

310

312 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;

313 else

314 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;

315

316 return false;

317 }

318

320 const auto &Src = S.Current->getSource(OpPC);

321

323 S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;

324 } else if (!S.checkingPotentialConstantExpression()) {

326 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;

327

328 if (IsTemp)

329 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);

330 else

331 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);

332 }

333

334 return false;

335 }

336

337 return true;

338}

339

341 assert(Desc);

342

344 if (D || D->hasGlobalStorage())

345 return true;

346

347 if (D == S.EvaluatingDecl)

348 return true;

349

350 if (D->isConstexpr())

351 return true;

352

353

354

355

356 if (const auto *VD = dyn_cast_if_present(S.EvaluatingDecl);

357 VD && VD->isConstexpr() && S.getLangOpts().C23)

359

363 if (!IsConstant) {

365 return false;

366 }

367 return true;

368 }

369

370 if (IsConstant) {

372 S.CCEDiag(S.Current->getLocation(OpPC),

374 ? diag::note_constexpr_ltor_non_constexpr

375 : diag::note_constexpr_ltor_non_integral,

376 1)

377 << D << T;

378 S.Note(D->getLocation(), diag::note_declared_at);

379 } else {

380 S.CCEDiag(S.Current->getLocation(OpPC));

381 }

382 return true;

383 }

384

389 return false;

390 }

391 return true;

392 }

393

395 return false;

396}

397

400 return true;

402}

403

407 return true;

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

409 S.FFDiag(Loc, diag::note_constexpr_null_subobject)

410 << CSK << S.Current->getRange(OpPC);

411

412 return false;

413}

414

418 return true;

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

421 S.FFDiag(Loc, diag::note_constexpr_access_past_end)

422 << AK << S.Current->getRange(OpPC);

423 }

424 return false;

425}

426

430 return true;

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

432 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)

433 << CSK << S.Current->getRange(OpPC);

434 return false;

435}

436

440 return true;

441

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

443 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)

444 << CSK << S.Current->getRange(OpPC);

445 return false;

446}

447

449 uint32_t Offset) {

452

453

454

455 if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)

456 return true;

457

458 const auto *E = cast(S.Current->getExpr(OpPC));

461

462 S.CCEDiag(E, diag::note_constexpr_invalid_downcast)

463 << MostDerivedQT << TargetQT;

464

465 return false;

466}

467

469 assert(Ptr.isLive() && "Pointer is not live");

471 return true;

472

473

474

475

476

477 if (S.Current->getFunction()) {

480 Func && (Func->isConstructor() || Func->isDestructor()) &&

481 Ptr.block() == Frame->getThis().block()) {

482 return true;

483 }

484 }

485 }

486

488 return false;

489

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

492 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;

493 return false;

494}

495

497 assert(Ptr.isLive() && "Pointer is not live");

499 return true;

500

501

502

505 return true;

506

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

509 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;

510 S.Note(Field->getLocation(), diag::note_declared_at);

511 return false;

512}

513

516 assert(Ptr.isLive());

517

518

519

521 return true;

522

525 return true;

526

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

529 S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;

530 else

531 S.FFDiag(Loc);

532 return false;

533}

534

537 assert(Ptr.isLive());

538

540 return true;

541

543 VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {

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

545 if (VD->getAnyInitializer()) {

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

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

548 } else {

550 }

551 return false;

552 }

553

554 if (!S.checkingPotentialConstantExpression()) {

555 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)

556 << AK << true << S.Current->getRange(OpPC);

557 }

558 return false;

559}

560

563 return true;

564

567 if ((!VD->hasConstantInitialization() &&

568 VD->mightBeUsableInConstantExpressions(S.getASTContext())) ||

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

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

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

574 }

575 return false;

576}

577

580 return true;

581

583 assert(VD);

584 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)

585 << VD;

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

587

588 return false;

589}

590

593 if (CheckLive(S, OpPC, Ptr, AK))

594 return false;

596 return false;

598 return false;

600 return false;

602 return false;

604 return false;

606 return false;

608 return false;

610 return false;

612 return false;

614 return false;

615 return true;

616}

617

618

619

622 return false;

624 return false;

625

627 return false;

629 return false;

631 return false;

633 return false;

635 return false;

637 return false;

639 return false;

641 return false;

642 return true;

643}

644

647 return false;

649 return false;

651 return false;

653 return false;

655 return false;

657 return false;

658 return true;

659}

660

663 return false;

666 return false;

668 return false;

669 }

670 return true;

671}

672

675 return false;

677 return false;

678 return true;

679}

680

682

685 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);

686 return false;

687 }

688

691 return true;

692

693

695 return true;

696

700

701

703 return false;

704

705

706

707 const auto *CD = dyn_cast(DiagDecl);

708 if (CD && CD->isInheritingConstructor()) {

709 const auto *Inherited = CD->getInheritedConstructor().getConstructor();

710 if (!Inherited->isConstexpr())

711 DiagDecl = CD = Inherited;

712 }

713

714

715

716

717 if (CD && CD->isInheritingConstructor()) {

718 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)

719 << CD->getInheritedConstructor().getConstructor()->getParent();

720 S.Note(DiagDecl->getLocation(), diag::note_declared_at);

721 } else {

722

723

724

727 S.checkingPotentialConstantExpression())

728 return false;

729

730

731

734 return false;

735

736 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)

738

741 diag::note_declared_at);

742 else

743 S.Note(DiagDecl->getLocation(), diag::note_declared_at);

744 }

745 } else {

746 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);

747 }

748

749 return false;

750}

751

753 if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {

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

755 diag::note_constexpr_depth_limit_exceeded)

757 return false;

758 }

759

760 return true;

761}

762

764 if (This.isZero())

765 return true;

766

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

768

769 bool IsImplicit = false;

770 if (const auto *E = dyn_cast_if_present(Loc.asExpr()))

771 IsImplicit = E->isImplicit();

772

774 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;

775 else

776 S.FFDiag(Loc);

777

778 return false;

779}

780

783 return true;

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

785 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;

786 S.Note(MD->getLocation(), diag::note_declared_at);

787 return false;

788}

789

791 APFloat::opStatus Status, FPOptions FPO) {

792

793

794

795

796 if (Result.isNan()) {

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

798 S.CCEDiag(E, diag::note_constexpr_float_arithmetic)

799 << true << S.Current->getRange(OpPC);

800 return S.noteUndefinedBehavior();

801 }

802

803

804

805 if (S.inConstantContext())

806 return true;

807

808 if ((Status & APFloat::opInexact) &&

810

811

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

813 S.FFDiag(E, diag::note_constexpr_dynamic_rounding);

814 return false;

815 }

816

817 if ((Status != APFloat::opOK) &&

820 FPO.getAllowFEnvAccess())) {

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

822 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);

823 return false;

824 }

825

826 if ((Status & APFloat::opStatus::opInvalidOp) &&

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

829

830 S.FFDiag(E);

831 return false;

832 }

833

834 return true;

835}

836

839 return true;

840

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

842 S.CCEDiag(E, diag::note_constexpr_new);

843 return true;

844}

845

849 const Expr *NewExpr) {

850 if (AllocForm == DeleteForm)

851 return true;

852

854

855

856

857 if (D->isArray()) {

858 QualType ElemQT = D->getType()->getPointeeType();

860 ElemQT, APInt(64, static_cast<uint64_t>(D->getNumElems()), false),

862 } else

863 TypeToDiagnose = D->getType()->getPointeeType();

864

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

866 S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)

867 << static_cast<int>(DeleteForm) << static_cast<int>(AllocForm)

868 << TypeToDiagnose;

869 S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)

871 return false;

872}

873

876

877

878 if (isa_and_nonnull(Source))

879 return true;

880 if (const CallExpr *CE = dyn_cast_if_present(Source);

881 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)

882 return true;

883

884

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

886 S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)

888

890 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);

891 else

892 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);

893 return false;

894}

895

896

897

901}

902

906 return true;

907

910 if (D)

911 return false;

912

915

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

919 S.FFDiag(E, diag::note_constexpr_modify_global);

920 }

921 return false;

922}

923

925 const CallExpr *CE, unsigned ArgSize) {

928 unsigned Offset = 0;

929 unsigned Index = 0;

930 for (const Expr *Arg : Args) {

931 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {

932 const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);

933 if (ArgPtr.isZero()) {

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

936 return false;

937 }

938 }

939

941 ++Index;

942 }

943 return true;

944}

945

946

947

948

949

950

956 assert(R);

957

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

960 S.FFDiag(Loc, diag::note_constexpr_double_destroy);

961 return false;

962 }

963

964

967 const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);

968 if (!DtorFunc)

969 return false;

970

971 S.Stk.push<Pointer>(BasePtr);

972 if (Call(S, OpPC, DtorFunc, 0))

973 return false;

974 }

975 return true;

976}

977

979 assert(B);

981

983 return true;

984

986

989 assert(ElemDesc->isRecord());

990

992 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {

994 return false;

995 }

996 return true;

997 }

998

1001}

1002

1006 return DD->isVirtual();

1007 return false;

1008}

1009

1011 bool IsGlobalDelete) {

1013 return false;

1014

1015 const Expr *Source = nullptr;

1016 const Block *BlockToDelete = nullptr;

1017 {

1018

1019

1021

1022

1024 return true;

1025

1026

1030

1031

1032

1033 if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&

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

1036 diag::note_constexpr_delete_base_nonvirt_dtor)

1037 << InitialType << Ptr.getType();

1038 return false;

1039 }

1040

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

1043 S.FFDiag(Loc, diag::note_constexpr_delete_subobject)

1045 return false;

1046 }

1047

1049 BlockToDelete = Ptr.block();

1050

1052 return false;

1053

1054

1055

1057 if (!DeleteIsArrayForm && !IsGlobalDelete) {

1061 return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;

1062 return nullptr;

1063 };

1064

1067 VirtualDelete &&

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

1070 diag::note_constexpr_new_non_replaceable)

1071 << isa(VirtualDelete) << VirtualDelete;

1072 return false;

1073 }

1074 }

1075 }

1076 assert(Source);

1077 assert(BlockToDelete);

1078

1079

1081 return false;

1082

1085 std::optionalDynamicAllocator::Form AllocForm =

1086 Allocator.getAllocationForm(Source);

1087

1088 if (!Allocator.deallocate(Source, BlockToDelete, S)) {

1089

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

1091 S.FFDiag(Loc, diag::note_constexpr_double_delete);

1092 return false;

1093 }

1094

1095 assert(AllocForm);

1100 Source);

1101}

1102

1105 llvm::APInt Min;

1106 llvm::APInt Max;

1107

1108 if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())

1109 return;

1110

1113

1115 (Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {

1117 S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)

1118 << llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()

1119 << ED;

1122 S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)

1123 << llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()

1124 << ED;

1125 }

1126}

1127

1129 assert(T);

1131

1132

1133

1134

1135

1136

1137

1138

1139

1140

1141

1142

1143

1144

1145

1146 if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&

1147 S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl) {

1148 return true;

1149 }

1150

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

1153 S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();

1154 else

1155 S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);

1156 return false;

1157}

1158

1160 uint32_t Off) {

1161 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&

1163 return false;

1164

1166 return false;

1168 return false;

1170 return false;

1172 return false;

1173

1176 return true;

1177 }

1178

1180

1181

1182

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

1184 diag::note_constexpr_access_unreadable_object)

1186 return false;

1187 }

1188

1190 return false;

1191

1193 return true;

1194}

1195

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

1198 return getField(S, OpPC, Ptr, Off);

1199}

1200

1202 const auto &Ptr = S.Stk.pop<Pointer>();

1203 return getField(S, OpPC, Ptr, Off);

1204}

1205

1207 const Pointer &ThisPtr) {

1208 assert(Func->isConstructor());

1209

1211

1212

1213

1214 if (D->ElemRecord)

1215 return true;

1216

1217 if (D->ElemRecord->getNumVirtualBases() == 0)

1218 return true;

1219

1220 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base)

1221 << Func->getParentDecl();

1222 return false;

1223}

1224

1226 uint32_t VarArgSize) {

1227 if (Func->hasThisPointer()) {

1228 size_t ArgSize = Func->getArgSize() + VarArgSize;

1229 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);

1230 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

1231

1232

1233

1234

1235

1236 if (!(S.Current->getFunction() &&

1237 S.Current->getFunction()->isLambdaStaticInvoker() &&

1238 Func->isLambdaCallOperator())) {

1240 return false;

1241 }

1242

1243 if (S.checkingPotentialConstantExpression())

1244 return false;

1245 }

1246

1248 return false;

1249

1251 return false;

1252

1253 auto NewFrame = std::make_unique(S, Func, OpPC, VarArgSize);

1255 S.Current = NewFrame.get();

1256

1257

1258

1259

1261 NewFrame.release();

1262 assert(S.Current == FrameBefore);

1263 return true;

1264 }

1265

1266

1267

1268 S.Current = FrameBefore;

1269 return false;

1270}

1271

1273 uint32_t VarArgSize) {

1274 assert(Func);

1275 auto cleanup = [&]() -> bool {

1277 return false;

1278 };

1279

1280 if (Func->hasThisPointer()) {

1281 size_t ArgSize = Func->getArgSize() + VarArgSize;

1282 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);

1283

1284 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

1285

1286

1287

1288

1289

1290 if (S.Current->getFunction() &&

1291 S.Current->getFunction()->isLambdaStaticInvoker() &&

1292 Func->isLambdaCallOperator()) {

1293 assert(ThisPtr.isZero());

1294 } else {

1296 return cleanup();

1297 }

1298

1300 return false;

1301 }

1302

1304 return cleanup();

1305

1306

1307

1308

1309 if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&

1310 Func->isConstructor())

1311 return cleanup();

1312

1314 return cleanup();

1315

1316 auto NewFrame = std::make_unique(S, Func, OpPC, VarArgSize);

1318 S.Current = NewFrame.get();

1319

1321

1322

1323

1325 NewFrame.release();

1326 assert(S.Current == FrameBefore);

1327 return true;

1328 }

1329

1330

1331

1332 S.Current = FrameBefore;

1333 return false;

1334}

1335

1337 uint32_t VarArgSize) {

1338 assert(Func->hasThisPointer());

1339 assert(Func->isVirtual());

1340 size_t ArgSize = Func->getArgSize() + VarArgSize;

1341 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);

1343

1345 {

1346 Pointer TypePtr = ThisPtr;

1348 TypePtr = TypePtr.getBase();

1349

1352 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();

1353 else

1354 DynamicDecl = DynamicType->getAsCXXRecordDecl();

1355 }

1356 assert(DynamicDecl);

1357

1358 const auto *StaticDecl = cast(Func->getParentDecl());

1359 const auto *InitialFunction = cast(Func->getDecl());

1360 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(

1361 DynamicDecl, StaticDecl, InitialFunction);

1362

1363 if (Overrider != InitialFunction) {

1364

1365

1366

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

1369 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();

1370 }

1371

1372 Func = S.getContext().getOrCreateFunction(Overrider);

1373

1375 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();

1376 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {

1377

1378

1379

1380 while (ThisPtr.isBaseClass())

1381 ThisPtr = ThisPtr.getBase();

1382 }

1383 }

1384

1385 if (Call(S, OpPC, Func, VarArgSize))

1386 return false;

1387

1388

1389

1390 if (Overrider != InitialFunction &&

1392 InitialFunction->getReturnType()->isPointerOrReferenceType()) {

1393 QualType OverriderPointeeType =

1395 QualType InitialPointeeType =

1397

1398

1399

1400

1401 unsigned Offset = S.getContext().collectBaseOffset(

1405 }

1406

1407 return true;

1408}

1409

1411 const CallExpr *CE, uint32_t BuiltinID) {

1412

1413

1414 if (BuiltinID == Builtin::BI__builtin_operator_new &&

1415 S.checkingPotentialConstantExpression())

1416 return false;

1417 auto NewFrame = std::make_unique(S, Func, OpPC);

1418

1420 S.Current = NewFrame.get();

1421

1423

1424 NewFrame.release();

1425

1426 assert(S.Current == FrameBefore);

1427 return true;

1428 }

1429

1430

1431

1432 S.Current = FrameBefore;

1433 return false;

1434}

1435

1439

1441 if (!F) {

1442 const auto *E = cast(S.Current->getExpr(OpPC));

1443 S.FFDiag(E, diag::note_constexpr_null_callee)

1445 return false;

1446 }

1447

1448 if (!FuncPtr.isValid() || !F->getDecl())

1449 return Invalid(S, OpPC);

1450

1451 assert(F);

1452

1453

1454

1455 if (S.Ctx.classify(F->getDecl()->getReturnType()) !=

1456 S.Ctx.classify(CE->getType()))

1457 return false;

1458

1459

1460 if (F->hasNonNullAttr()) {

1462 return false;

1463 }

1464

1465 assert(ArgSize >= F->getWrittenArgSize());

1466 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();

1467

1468

1469

1470 if (F->isThisPointerExplicit())

1472

1473 if (F->isVirtual())

1474 return CallVirt(S, OpPC, F, VarArgSize);

1475

1476 return Call(S, OpPC, F, VarArgSize);

1477}

1478

1480 std::optional<uint64_t> ArraySize) {

1482

1484 return false;

1485

1487 return false;

1488

1489 const auto *NewExpr = cast(E);

1491

1494

1496 }

1497

1500 if (ArraySize) {

1502 NewExpr->getAllocatedType(),

1503 APInt(64, static_cast<uint64_t>(*ArraySize), false), nullptr,

1505 } else {

1506 AllocType = NewExpr->getAllocatedType();

1507 }

1508

1509 unsigned StorageSize = 1;

1510 unsigned AllocSize = 1;

1511 if (const auto *CAT = dyn_cast(AllocType))

1512 AllocSize = CAT->getZExtSize();

1513 if (const auto *CAT = dyn_cast(StorageType))

1514 StorageSize = CAT->getZExtSize();

1515

1516 if (AllocSize > StorageSize ||

1519 S.FFDiag(S.Current->getLocation(OpPC),

1520 diag::note_constexpr_placement_new_wrong_type)

1521 << StorageType << AllocType;

1522 return false;

1523 }

1524

1525

1528

1529 return true;

1530}

1531

1533 assert(E);

1534

1536 return true;

1537

1538 const auto &Loc = S.Current->getSource(OpPC);

1539

1540 if (const auto *NewExpr = dyn_cast(E)) {

1541 const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();

1542

1543 if (!S.getLangOpts().CPlusPlus26 && NewExpr->getNumPlacementArgs() > 0) {

1544

1545 if (S.Current->isStdFunction())

1546 return true;

1547 S.FFDiag(Loc, diag::note_constexpr_new_placement)

1549 } else if (NewExpr->getNumPlacementArgs() == 1 &&

1550 !OperatorNew->isReservedGlobalPlacementOperator()) {

1551 S.FFDiag(Loc, diag::note_constexpr_new_placement)

1553 } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {

1554 S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)

1555 << isa(OperatorNew) << OperatorNew;

1556 }

1557 } else {

1558 const auto *DeleteExpr = cast(E);

1559 const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();

1560 if (!OperatorDelete->isReplaceableGlobalAllocationFunction()) {

1561 S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)

1562 << isa(OperatorDelete) << OperatorDelete;

1563 }

1564 }

1565

1566 return false;

1567}

1568

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

1572 if (S.checkingForUndefinedBehavior()) {

1574 E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)

1576 }

1577 S.CCEDiag(E, diag::note_constexpr_overflow)

1579 return S.noteUndefinedBehavior();

1580}

1581

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

1584 S.FFDiag(Loc,

1585 diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)

1586 << Index;

1587 return false;

1588}

1589

1591 const Pointer &Ptr, unsigned BitWidth) {

1593 return false;

1594

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

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

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

1598

1600

1602 BitWidth)

1603 return Invalid(S, OpPC);

1604 }

1605 return true;

1606}

1607

1610

1612 return false;

1613

1616 return true;

1617}

1618

1621

1623 return false;

1624

1627 return true;

1628}

1629

1631 bool TargetIsUCharOrByte) {

1632

1633 if (!HasIndeterminateBits)

1634 return true;

1635

1636

1637 if (TargetIsUCharOrByte)

1638 return true;

1639

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

1642 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)

1644 return false;

1645}

1646

1648 const Type *TypeInfoType) {

1649 S.Stk.push<Pointer>(TypePtr, TypeInfoType);

1650 return true;

1651}

1652

1654 const auto &P = S.Stk.pop<Pointer>();

1655

1656 if (P.isBlockPointer())

1657 return false;

1658

1659 if (P.isDummy()) {

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

1663 diag::note_constexpr_polymorphic_unknown_dynamic_type)

1667 return false;

1668 }

1669

1670 S.Stk.push<Pointer>(P.getType().getTypePtr(), TypeInfoType);

1671 return true;

1672}

1673

1675 const auto *E = cast(S.Current->getExpr(OpPC));

1676 S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)

1677 << E->getExprOperand()->getType()

1679 return false;

1680}

1681

1682

1683#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)

1684#pragma optimize("", off)

1685#endif

1687

1688

1689

1690

1691 const InterpFrame *StartFrame = S.Current;

1692 assert(!S.Current->isRoot());

1693 CodePtr PC = S.Current->getPC();

1694

1695

1696 if (!PC)

1697 return true;

1698

1699 for (;;) {

1702

1703 switch (Op) {

1704#define GET_INTERP

1705#include "Opcodes.inc"

1706#undef GET_INTERP

1707 }

1708 }

1709}

1710

1711#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)

1712#pragma optimize("", on)

1713#endif

1714

1715}

1716}

Defines the clang::ASTContext interface.

Defines the clang::Expr interface and subclasses for C++ expressions.

static const FunctionDecl * getVirtualOperatorDelete(QualType T)

static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset)

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

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

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

static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset)

static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD)

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

static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset)

static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, const ValueDecl *VD)

static bool RetValue(InterpState &S, CodePtr &Pt)

#define TYPE_SWITCH(Expr, B)

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const

Return the uniqued reference to the type for an lvalue reference to the specified type.

Builtin::Context & BuiltinInfo

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.

QualType getBaseElementType(const ArrayType *VAT) const

Return the innermost element type of an array type.

bool hasSimilarType(QualType T1, QualType T2) const

Determine if two types are similar, according to the C++ rules.

DiagnosticsEngine & getDiagnostics() const

const TargetInfo & getTargetInfo() const

bool hasCustomTypechecking(unsigned ID) const

Determines whether this builtin has custom typechecking.

Represents a C++ destructor within a class.

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

Represents a C++ struct/union/class.

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

unsigned getBuiltinCallee() const

getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.

unsigned getNumArgs() const

getNumArgs - Return the number of actual arguments to this call.

Expr ** getArgs()

Retrieve the call arguments.

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

bool isInvalidDecl() const

SourceLocation getLocation() const

virtual SourceRange getSourceRange() const LLVM_READONLY

Source range that this declaration covers.

DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)

Issue the message to the client.

unsigned getNumNegativeBits() const

Returns the width in bits required to store all the negative enumerators of this enum.

void getValueRange(llvm::APInt &Max, llvm::APInt &Min) const

Calculates the [Min,Max) values the enum can store based on the NumPositiveBits and NumNegativeBits.

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...

LangOptions::FPExceptionModeKind getExceptionMode() const

RoundingMode getRoundingMode() const

Represents a member of a struct/union/class.

Represents a function declaration or definition.

QualType getReturnType() const

bool isTrivial() const

Whether this function is "trivial" in some specialized C++ senses.

StorageClass getStorageClass() const

Returns the storage class as written in the source.

bool isConstexpr() const

Whether this is a (C++11) constexpr function or constexpr constructor.

bool isPureVirtual() const

Whether this virtual function is pure, i.e.

FunctionDecl * getDefinition()

Get the definition for this declaration.

bool isReplaceableGlobalAllocationFunction(std::optional< unsigned > *AlignmentParam=nullptr, bool *IsNothrow=nullptr) const

Determines whether this function is one of the replaceable global allocation functions: void *operato...

bool hasBody(const FunctionDecl *&Definition) const

Returns true if the function has a body.

bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const

Returns true if the function has a definition that does not need to be instantiated.

@ FPE_Ignore

Assume that floating-point exceptions are masked.

A (possibly-)qualified type.

bool isVolatileQualified() const

Determine whether this type is volatile-qualified.

bool isConstant(const ASTContext &Ctx) const

ASTContext & getASTContext() const

const LangOptions & getLangOpts() const

Encodes a location in the source.

SourceRange getSourceRange() const LLVM_READONLY

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

uint64_t getPointerWidth(LangAS AddrSpace) const

Return the width of pointers on this target, for the specified address space.

The base class of the type hierarchy.

CXXRecordDecl * getAsCXXRecordDecl() const

Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...

bool isPointerType() const

QualType getPointeeType() const

If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.

bool isIntegralOrEnumerationType() const

Determine whether this type is an integral or enumeration type.

bool isPointerOrReferenceType() const

RecordDecl * getAsRecordDecl() const

Retrieves the RecordDecl this type refers to.

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

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

unsigned getSize() const

Returns the size of the block.

const Descriptor * getDescriptor() const

Returns the block's descriptor.

unsigned getEvalID() const

The Evaluation ID this block was created in.

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.

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

Base class for stack frames, shared between VM and walker.

const Function * getFunction() const

const FunctionDecl * getDecl() const

Returns the original FunctionDecl.

bool hasBody() const

Checks if the function already has a body attached.

bool isVirtual() const

Checks if the function is virtual.

bool isConstexpr() const

Checks if the function is valid to call in constexpr.

bool isLambdaStaticInvoker() const

Returns whether this function is a lambda static invoker, which we generate custom byte code for.

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

Frame storing local variables.

A pointer to a memory block, live or dead.

Pointer narrow() const

Restricts the scope of an array element pointer.

bool isInitialized() const

Checks if an object was initialized.

bool isStatic() const

Checks if the storage is static.

bool isDynamic() const

Checks if the storage has been dynamically allocated.

Pointer atIndex(uint64_t Idx) const

Offsets a pointer inside an array.

bool isDummy() const

Checks if the pointer points to a dummy value.

bool isExtern() const

Checks if the storage is extern.

bool isActive() const

Checks if the object is active.

bool isConst() const

Checks if an object or a subfield is mutable.

Pointer atField(unsigned Off) const

Creates a pointer to a field.

bool isMutable() const

Checks if the field is mutable.

bool isUnknownSizeArray() const

Checks if the structure is an array of unknown size.

bool isIntegralPointer() const

QualType getType() const

Returns the type of the innermost field.

bool isArrayElement() const

Checks if the pointer points to an array.

bool isLive() const

Checks if the pointer is live.

bool isStaticTemporary() const

Checks if the storage is a static temporary.

Pointer getBase() const

Returns a pointer to the object of which this pointer is a field.

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.

const IntPointer & asIntPointer() const

bool isRoot() const

Pointer points directly to a block.

const Descriptor * getDeclDesc() const

Accessor for information about the declaration site.

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

Checks if both given pointers point to the same block.

bool isOnePastEnd() const

Checks if the index is one past end.

uint64_t getIntegerRepresentation() const

const FieldDecl * getField() const

Returns the field information.

bool isElementPastEnd() const

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

bool isBlockPointer() const

bool isTemporary() const

Checks if the storage is temporary.

SourceLocation getDeclLoc() const

const Block * block() const

Pointer getDeclPtr() const

const Descriptor * getFieldDesc() const

Accessors for information about the innermost field.

std::optional< unsigned > getDeclID() const

Returns the declaration ID.

bool isBaseClass() const

Checks if a structure is a base class.

bool isField() const

Checks if the item is a field in an object.

const Record * getRecord() const

Returns the record descriptor of a class.

Structure/Class descriptor.

bool isUnion() const

Checks if the record is a union.

const CXXDestructorDecl * getDestructor() const

Returns the destructor of the record, if any.

llvm::iterator_range< const_field_iter > fields() const

Describes the statement/declaration an opcode was generated from.

Defines the clang::TargetInfo interface.

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

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

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

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

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 runRecordDestructor(InterpState &S, CodePtr OpPC, const Pointer &BasePtr, const Descriptor *Desc)

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

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 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 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 CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)

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

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

static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B)

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

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

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

Checks if a pointer points to a mutable field.

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

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

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

static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Off)

static bool hasVirtualDestructor(QualType T)

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

Checks if a value can be loaded from a block.

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

constexpr size_t align(size_t Size)

Aligns a size to the pointer alignment.

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

Checks if a pointer is in range.

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

Checks if a method is pure virtual.

bool This(InterpState &S, CodePtr OpPC)

bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)

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

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

Checks if a pointer is live and accessible.

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 CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte)

static void popArg(InterpState &S, const Expr *Arg)

static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, const Pointer &ThisPtr)

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

PrimType

Enumeration of the primitive types of the VM.

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 CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)

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

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 CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)

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 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 CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)

Checks if a pointer is a dummy pointer.

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

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

llvm::BitVector collectNonNullArgs(const FunctionDecl *F, const llvm::ArrayRef< const Expr * > &Args)

size_t primSize(PrimType Type)

Returns the size of a primitive type in bytes.

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 CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

Checks if the variable has externally defined storage.

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

Checks if a method can be called.

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

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

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

Checks if a pointer points to const storage.

bool Interpret(InterpState &S)

Interpreter entry point.

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

Checks if a method can be invoked on an object.

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

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

llvm::StringRef getAsString(SyncScope S)

Describes a memory block created by an allocation site.

unsigned getNumElems() const

Returns the number of elements stored in the block.

bool isPrimitive() const

Checks if the descriptor is of a primitive.

bool isCompositeArray() const

Checks if the descriptor is of an array of composites.

const ValueDecl * asValueDecl() const

const Descriptor *const ElemDesc

Descriptor of the array element.

unsigned getMetadataSize() const

Returns the size of the metadata.

bool isPrimitiveArray() const

Checks if the descriptor is of an array of primitives.

const VarDecl * asVarDecl() const

bool isRecord() const

Checks if the descriptor is of a record.

const Record *const ElemRecord

Pointer to the record, if block contains records.

const Expr * asExpr() const

IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const