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;
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
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() || .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() || .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 }
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 }
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
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
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 ((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 ((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 std::memcpy(&TargetSemantics, &FPS, sizeof(TargetSemantics));
2146
2147 const auto &Source = S.Stk.pop<FixedPoint>();
2148
2149 bool Overflow;
2150 FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
2151
2153 return false;
2154
2156 return true;
2157}
2158
2159
2160
2161template <PrimType Name, class T = typename PrimConv::T>
2165 return true;
2166}
2167
2168template <PrimType Name, class T = typename PrimConv::T>
2172 return true;
2173}
2174
2175template <PrimType Name, class T = typename PrimConv::T>
2177 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2178 const T &From = S.Stk.pop<T>();
2179 APSInt FromAP = From.toAPSInt();
2181
2183 auto Status =
2186
2188}
2189
2190template <PrimType Name, class T = typename PrimConv::T>
2193
2194 if constexpr (std::is_same_v<T, Boolean>) {
2196 return true;
2197 } else {
2199 !T::isSigned());
2201
2202
2203 if ((Status & APFloat::opStatus::opInvalidOp)) {
2204 const Expr *E = S.Current->getExpr(OpPC);
2206
2207 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2208 if (S.noteUndefinedBehavior()) {
2210 return true;
2211 }
2212 return false;
2213 }
2214
2218 }
2219}
2220
2222 uint32_t BitWidth, uint32_t FPOI) {
2224
2225 APSInt Result(BitWidth, true);
2227
2228
2229 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2231
2235}
2236
2238 uint32_t BitWidth, uint32_t FPOI) {
2240
2241 APSInt Result(BitWidth, false);
2243
2244
2245 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2247
2251}
2252
2254 const Pointer &Ptr, unsigned BitWidth);
2257
2258template <PrimType Name, class T = typename PrimConv::T>
2261
2263 return false;
2264
2266 return true;
2267}
2268
2269template <PrimType Name, class T = typename PrimConv::T>
2271 uint32_t FPS) {
2272 const T &Int = S.Stk.pop<T>();
2273
2275 std::memcpy(&Sem, &FPS, sizeof(Sem));
2276
2277 bool Overflow;
2279
2281 return false;
2282
2284 return true;
2285}
2286
2288 uint32_t FPS) {
2290
2292 std::memcpy(&Sem, &FPS, sizeof(Sem));
2293
2294 bool Overflow;
2296
2298 return false;
2299
2301 return true;
2302}
2303
2305 const llvm::fltSemantics *Sem) {
2306 const auto &Fixed = S.Stk.pop<FixedPoint>();
2307
2308 S.Stk.push<Floating>(Fixed.toFloat(Sem));
2309 return true;
2310}
2311
2312template <PrimType Name, class T = typename PrimConv::T>
2314 const auto &Fixed = S.Stk.pop<FixedPoint>();
2315
2316 bool Overflow;
2317 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2318
2320 return false;
2321
2323 return true;
2324}
2325
2327 const auto &Ptr = S.Stk.peek<Pointer>();
2328
2329 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2330 bool HasValidResult = !Ptr.isZero();
2331
2332 if (HasValidResult) {
2333
2334 } else if (!S.getLangOpts().CPlusPlus26) {
2335 const SourceInfo &E = S.Current->getSource(OpPC);
2336 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2337 << 3 << "'void *'" << S.Current->getRange(OpPC);
2338 }
2339 } else {
2340 const SourceInfo &E = S.Current->getSource(OpPC);
2341 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2342 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2343 }
2344
2345 return true;
2346}
2347
2348
2349
2350
2351
2352template <PrimType Name, class T = typename PrimConv::T>
2354 S.Stk.push<T>(T::zero());
2355 return true;
2356}
2357
2360 return true;
2361}
2362
2365 return true;
2366}
2367
2368template <PrimType Name, class T = typename PrimConv::T>
2371
2372
2373 S.Stk.push<T>(Value, Desc);
2374 return true;
2375}
2376
2377template <PrimType Name, class T = typename PrimConv::T>
2379 const auto &P = S.Stk.pop<T>();
2380 if (P.isWeak())
2381 return false;
2383 return true;
2384}
2385
2386
2387
2388
2389
2391
2392 if (S.checkingPotentialConstantExpression()) {
2393 return false;
2394 }
2395
2396 const Pointer &This = S.Current->getThis();
2398 return false;
2399
2400
2401 if (.isDummy()) {
2402 assert(isa(S.Current->getFunction()->getDecl()));
2403 assert(This.getRecord());
2404 assert(
2405 This.getRecord()->getDecl() ==
2406 cast(S.Current->getFunction()->getDecl())->getParent());
2407 }
2408
2410 return true;
2411}
2412
2414 assert(S.Current->getFunction()->hasRVO());
2415 if (S.checkingPotentialConstantExpression())
2416 return false;
2417 S.Stk.push<Pointer>(S.Current->getRVOPtr());
2418 return true;
2419}
2420
2421
2422
2423
2424
2425template <class LT, class RT, ShiftDir Dir>
2427 const unsigned Bits = LHS.bitWidth();
2428
2429
2431 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2432 RHS.bitWidth(), &RHS);
2433
2434 if (RHS.isNegative()) {
2435
2436
2437 const SourceInfo &Loc = S.Current->getSource(OpPC);
2438 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2439 if (!S.noteUndefinedBehavior())
2440 return false;
2441 RHS = -RHS;
2444 S, OpPC, LHS, RHS);
2445 }
2446
2447 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
2448 return false;
2449
2450
2451
2452
2453
2454
2455
2456 typename LT::AsUnsigned R;
2457 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2459 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2461 if (LHS.isNegative())
2462 R = LT::AsUnsigned::zero(LHS.bitWidth());
2463 else {
2464 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2465 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2466 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2467 }
2468 } else if (LHS.isNegative()) {
2469 if (LHS.isMin()) {
2470 R = LT::AsUnsigned::zero(LHS.bitWidth());
2471 } else {
2472
2473 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2474 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
2475 &R);
2476 R = -R;
2477 }
2478 } else {
2479
2480 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2481 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2482 }
2483 } else {
2484
2485 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2487 R = LT::AsUnsigned::from(-1);
2488 } else {
2489
2490 LT A;
2491 LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
2492 R = LT::AsUnsigned::from(A);
2493 }
2494 }
2495
2496 S.Stk.push<LT>(LT::from(R));
2497 return true;
2498}
2499
2500template <PrimType NameL, PrimType NameR>
2504 auto RHS = S.Stk.pop
2505 auto LHS = S.Stk.pop<LT>();
2506
2507 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2508}
2509
2510template <PrimType NameL, PrimType NameR>
2514 auto RHS = S.Stk.pop
2515 auto LHS = S.Stk.pop<LT>();
2516
2517 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2518}
2519
2521 const auto &RHS = S.Stk.pop<FixedPoint>();
2522 const auto &LHS = S.Stk.pop<FixedPoint>();
2523 llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
2524
2525 unsigned ShiftBitWidth =
2526 LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
2527
2528
2529
2530
2531 if (RHS.isNegative()) {
2532 S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
2533 << RHS.toAPSInt();
2534 } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
2535 ShiftBitWidth)) != RHS.toAPSInt()) {
2536 const Expr *E = S.Current->getExpr(OpPC);
2537 S.CCEDiag(E, diag::note_constexpr_large_shift)
2538 << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
2539 }
2540
2545 return false;
2546 } else {
2549 return false;
2550 }
2551
2553 return true;
2554}
2555
2556
2557
2558
2559
2561 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2562 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2563 return false;
2564}
2565
2566
2567
2568
2569
2573 return true;
2574}
2575
2579 return true;
2580}
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590template <PrimType Name, class T = typename PrimConv::T>
2592 const T &Offset = S.Stk.pop<T>();
2594
2595 if (!Ptr.isZero() && !Offset.isZero()) {
2597 return false;
2598 }
2599
2600 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2601 return false;
2602
2604}
2605
2606template <PrimType Name, class T = typename PrimConv::T>
2608 const T &Offset = S.Stk.pop<T>();
2610
2611 if (!Ptr.isZero() && !Offset.isZero()) {
2613 return false;
2614 }
2615
2616 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2617 return false;
2618
2620}
2621
2622template <PrimType Name, class T = typename PrimConv::T>
2625
2627 return false;
2628
2631 return true;
2632}
2633
2634template <PrimType Name, class T = typename PrimConv::T>
2637
2639 return false;
2640
2643 return true;
2644}
2645
2646template <PrimType Name, class T = typename PrimConv::T>
2648 uint32_t DestIndex, uint32_t Size) {
2649 const auto &SrcPtr = S.Stk.pop<Pointer>();
2650 const auto &DestPtr = S.Stk.peek<Pointer>();
2651
2652 for (uint32_t I = 0; I != Size; ++I) {
2654
2656 return false;
2657
2661 }
2662 return true;
2663}
2664
2665
2666
2669
2671 S.Stk.push<Pointer>(Ptr);
2672 return true;
2673 }
2674
2676 return false;
2677
2680 return true;
2681 }
2682
2683 const SourceInfo &E = S.Current->getSource(OpPC);
2684 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2685
2686 return false;
2687}
2688
2690 assert(Func);
2692 return true;
2693}
2694
2695template <PrimType Name, class T = typename PrimConv::T>
2697 const T &IntVal = S.Stk.pop<T>();
2698
2699 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2700 return true;
2701}
2702
2705 return true;
2706}
2707
2710
2711 S.Stk.push<Pointer>(MP.getBase());
2712 return true;
2713}
2714
2717
2718 const auto *FD = cast(MP.getDecl());
2719 const auto *Func = S.getContext().getOrCreateFunction(FD);
2720
2722 return true;
2723}
2724
2725
2726
2729 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2730 << S.Current->getRange(OpPC);
2731 return false;
2732}
2733
2736 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2737 << S.Current->getRange(OpPC);
2738 return false;
2739}
2740
2741
2744 return S.noteSideEffect();
2745}
2746
2747
2749 bool Fatal) {
2751
2752
2754 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2755 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2756 return !Fatal;
2757 }
2758 return false;
2759}
2760
2763 assert(DR);
2764
2766 const SourceInfo &Loc = S.Current->getSource(OpPC);
2767 const auto *VD = cast(DR->getDecl());
2768 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
2769 S.Note(VD->getLocation(), diag::note_declared_at);
2770 return false;
2771 }
2772
2774}
2775
2777 if (S.inConstantContext()) {
2778 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2779 const Expr *E = S.Current->getExpr(OpPC);
2780 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2781 }
2782 return false;
2783}
2784
2786 const auto Val = S.Stk.pop<Boolean>();
2787
2788 if (Val)
2789 return true;
2790
2791
2793 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2794 return false;
2795}
2796
2797template <PrimType Name, class T = typename PrimConv::T>
2800 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2801 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2802
2805 return false;
2806
2807 S.Stk.push<T>(T::from(Result));
2808
2809 return true;
2810}
2811
2812template <PrimType Name, class T = typename PrimConv::T>
2814 const T &Arg = S.Stk.peek<T>();
2815 if (!Arg.isZero())
2816 return true;
2817
2819 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2820
2821 return false;
2822}
2823
2826
2827template <PrimType Name, class T = typename PrimConv::T>
2829 assert(ED);
2831 const APSInt Val = S.Stk.peek<T>().toAPSInt();
2832
2833 if (S.inConstantContext())
2835 return true;
2836}
2837
2838
2839template <PrimType TIn, PrimType TOut>
2844
2845 const FromT &OldPtr = S.Stk.pop();
2846
2847 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2848 std::is_same_v<ToT, Pointer>) {
2849 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
2850 return true;
2851 } else if constexpr (std::is_same_v<FromT, Pointer> &&
2852 std::is_same_v<ToT, FunctionPointer>) {
2853 if (OldPtr.isFunctionPointer()) {
2854 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
2855 OldPtr.getByteOffset());
2856 return true;
2857 }
2858 }
2859
2860 S.Stk.push(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2861 return true;
2862}
2863
2865
2866
2867
2868
2870 VD->isStaticLocal());
2871
2872 if (VD == S.EvaluatingDecl)
2873 return true;
2874
2876 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
2878 return false;
2879 }
2880 return true;
2881}
2882
2884 assert(Desc);
2885
2887 return false;
2888
2890 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),
2892 assert(B);
2893
2895
2896 return true;
2897}
2898
2899template <PrimType Name, class SizeT = typename PrimConv::T>
2901 bool IsNoThrow) {
2903 return false;
2904
2905 SizeT NumElements = S.Stk.pop();
2907 if (!IsNoThrow)
2908 return false;
2909
2910
2911 S.Stk.push<Pointer>(0, nullptr);
2912 return true;
2913 }
2914
2917 Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
2919 assert(B);
2921
2922 return true;
2923}
2924
2925template <PrimType Name, class SizeT = typename PrimConv::T>
2927 bool IsNoThrow) {
2929 return false;
2930
2931 SizeT NumElements = S.Stk.pop();
2933 IsNoThrow)) {
2934 if (!IsNoThrow)
2935 return false;
2936
2937
2938 S.Stk.push<Pointer>(0, ElementDesc);
2939 return true;
2940 }
2941
2944 Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
2946 assert(B);
2947
2949
2950 return true;
2951}
2952
2953bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
2954 bool IsGlobalDelete);
2955
2958 return true;
2959}
2960
2962 return S.maybeDiagnoseDanglingAllocations();
2963}
2964
2965
2966
2968 std::optional<uint64_t> ArraySize = std::nullopt);
2969
2970template <PrimType Name, class T = typename PrimConv::T>
2972 const auto &Size = S.Stk.pop<T>();
2974}
2976
2977template <PrimType Name, class T = typename PrimConv::T>
2979 uint32_t ResultBitWidth,
2980 const llvm::fltSemantics *Sem) {
2982
2983 if ((S, OpPC, FromPtr))
2984 return false;
2985
2986 if constexpr (std::is_same_v<T, Pointer>) {
2987
2989 return true;
2990 } else {
2991
2992 size_t BuffSize = ResultBitWidth / 8;
2994 bool HasIndeterminateBits = false;
2995
2996 Bits FullBitWidth(ResultBitWidth);
2997 Bits BitWidth = FullBitWidth;
2998
2999 if constexpr (std::is_same_v<T, Floating>) {
3000 assert(Sem);
3001 BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3002 }
3003
3004 if ((S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3005 HasIndeterminateBits))
3006 return false;
3007
3008 if ((S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3009 return false;
3010
3011 if constexpr (std::is_same_v<T, Floating>) {
3012 assert(Sem);
3013 S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3014 } else {
3015 assert(!Sem);
3016 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3017 }
3018 return true;
3019 }
3020}
3021
3025
3026 if ((S, OpPC, FromPtr))
3027 return false;
3028
3030 return false;
3031
3032 return true;
3033}
3034
3035
3036bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
3037 const Type *TypeInfoType);
3038bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
3039bool DiagTypeid(InterpState &S, CodePtr OpPC);
3040
3041
3042
3043
3044
3046 if constexpr (std::is_pointer::value) {
3047 uint32_t ID = OpPC.read<uint32_t>();
3048 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3049 } else {
3051 }
3052}
3053
3057 return F;
3058}
3059
3060template <>
3061inline IntegralAP ReadArg<IntegralAP>(InterpState &S,
3062 CodePtr &OpPC) {
3064 OpPC += align(I.bytesToSerialize());
3065 return I;
3066}
3067
3068template <>
3069inline IntegralAP ReadArg<IntegralAP>(InterpState &S,
3070 CodePtr &OpPC) {
3072 OpPC += align(I.bytesToSerialize());
3073 return I;
3074}
3075
3076}
3077}
3078
3079#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 bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, bool *Overflow)
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)
- 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)
- 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)
- 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)
- Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
bool Div(InterpState &S, CodePtr OpPC)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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)
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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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.