1//===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Interp.h"
10#include "Function.h"
11#include "InterpFrame.h"
12#include "InterpShared.h"
13#include "InterpStack.h"
14#include "Opcode.h"
15#include "PrimType.h"
16#include "Program.h"
17#include "State.h"
18#include "clang/AST/ASTContext.h"
19#include "clang/AST/ASTDiagnostic.h"
20#include "clang/AST/CXXInheritance.h"
21#include "clang/AST/Expr.h"
22#include "clang/AST/ExprCXX.h"
23#include "llvm/ADT/APSInt.h"
24#include <limits>
25#include <vector>
26
27using namespace clang;
28
29using namespace clang;
30using namespace clang::interp;
31
32static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
33 llvm::report_fatal_error(reason: "Interpreter cannot return values");
34}
35
36//===----------------------------------------------------------------------===//
37// Jmp, Jt, Jf
38//===----------------------------------------------------------------------===//
39
40static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
41 PC += Offset;
42 return true;
43}
44
45static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
46 if (S.Stk.pop<bool>()) {
47 PC += Offset;
48 }
49 return true;
50}
51
52static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
53 if (!S.Stk.pop<bool>()) {
54 PC += Offset;
55 }
56 return true;
57}
58
59static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,
60 const ValueDecl *VD) {
61 const SourceInfo &E = S.Current->getSource(PC: OpPC);
62 S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
63 S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
64}
65
66static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
67 const ValueDecl *VD);
68static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
69 const ValueDecl *D) {
70 const SourceInfo &E = S.Current->getSource(PC: OpPC);
71
72 if (isa<ParmVarDecl>(Val: D)) {
73 if (S.getLangOpts().CPlusPlus11) {
74 S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
75 S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
76 } else {
77 S.FFDiag(SI: E);
78 }
79 } else if (const auto *VD = dyn_cast<VarDecl>(Val: D)) {
80 if (!VD->getType().isConstQualified()) {
81 diagnoseNonConstVariable(S, OpPC, VD);
82 return false;
83 }
84
85 // const, but no initializer.
86 if (!VD->getAnyInitializer()) {
87 diagnoseMissingInitializer(S, OpPC, VD);
88 return false;
89 }
90 }
91 return false;
92}
93
94static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
95 const ValueDecl *VD) {
96 if (!S.getLangOpts().CPlusPlus)
97 return;
98
99 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
100 if (const auto *VarD = dyn_cast<VarDecl>(Val: VD);
101 VarD && VarD->getType().isConstQualified() &&
102 !VarD->getAnyInitializer()) {
103 diagnoseMissingInitializer(S, OpPC, VD);
104 return;
105 }
106
107 if (VD->getType()->isIntegralOrEnumerationType()) {
108 S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
109 S.Note(VD->getLocation(), diag::note_declared_at);
110 return;
111 }
112
113 S.FFDiag(Loc,
114 S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
115 : diag::note_constexpr_ltor_non_integral,
116 1)
117 << VD << VD->getType();
118 S.Note(VD->getLocation(), diag::note_declared_at);
119}
120
121static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
122 AccessKinds AK) {
123 if (Ptr.isActive())
124 return true;
125
126 // Get the inactive field descriptor.
127 const FieldDecl *InactiveField = Ptr.getField();
128
129 // Walk up the pointer chain to find the union which is not active.
130 Pointer U = Ptr.getBase();
131 while (!U.isActive()) {
132 U = U.getBase();
133 }
134
135 // Find the active field of the union.
136 const Record *R = U.getRecord();
137 assert(R && R->isUnion() && "Not a union");
138 const FieldDecl *ActiveField = nullptr;
139 for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
140 const Pointer &Field = U.atField(Off: R->getField(I)->Offset);
141 if (Field.isActive()) {
142 ActiveField = Field.getField();
143 break;
144 }
145 }
146
147 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
148 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
149 << AK << InactiveField << !ActiveField << ActiveField;
150 return false;
151}
152
153static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
154 AccessKinds AK) {
155 if (auto ID = Ptr.getDeclID()) {
156 if (!Ptr.isStaticTemporary())
157 return true;
158
159 if (Ptr.getDeclDesc()->getType().isConstQualified())
160 return true;
161
162 if (S.P.getCurrentDecl() == ID)
163 return true;
164
165 const SourceInfo &E = S.Current->getSource(PC: OpPC);
166 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
167 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
168 return false;
169 }
170 return true;
171}
172
173static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
174 if (auto ID = Ptr.getDeclID()) {
175 if (!Ptr.isStatic())
176 return true;
177
178 if (S.P.getCurrentDecl() == ID)
179 return true;
180
181 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
182 return false;
183 }
184 return true;
185}
186
187namespace clang {
188namespace interp {
189static void popArg(InterpState &S, const Expr *Arg) {
190 PrimType Ty = S.getContext().classify(E: Arg).value_or(u: PT_Ptr);
191 TYPE_SWITCH(Ty, S.Stk.discard<T>());
192}
193
194void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
195 assert(S.Current);
196 const Function *CurFunc = S.Current->getFunction();
197 assert(CurFunc);
198
199 if (CurFunc->isUnevaluatedBuiltin())
200 return;
201
202 // Some builtin functions require us to only look at the call site, since
203 // the classified parameter types do not match.
204 if (CurFunc->isBuiltin()) {
205 const auto *CE =
206 cast<CallExpr>(Val: S.Current->Caller->getExpr(PC: S.Current->getRetPC()));
207 for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
208 const Expr *A = CE->getArg(Arg: I);
209 popArg(S, Arg: A);
210 }
211 return;
212 }
213
214 if (S.Current->Caller && CurFunc->isVariadic()) {
215 // CallExpr we're look for is at the return PC of the current function, i.e.
216 // in the caller.
217 // This code path should be executed very rarely.
218 unsigned NumVarArgs;
219 const Expr *const *Args = nullptr;
220 unsigned NumArgs = 0;
221 const Expr *CallSite = S.Current->Caller->getExpr(PC: S.Current->getRetPC());
222 if (const auto *CE = dyn_cast<CallExpr>(Val: CallSite)) {
223 Args = CE->getArgs();
224 NumArgs = CE->getNumArgs();
225 } else if (const auto *CE = dyn_cast<CXXConstructExpr>(Val: CallSite)) {
226 Args = CE->getArgs();
227 NumArgs = CE->getNumArgs();
228 } else
229 assert(false && "Can't get arguments from that expression type");
230
231 assert(NumArgs >= CurFunc->getNumWrittenParams());
232 NumVarArgs = NumArgs - CurFunc->getNumWrittenParams();
233 for (unsigned I = 0; I != NumVarArgs; ++I) {
234 const Expr *A = Args[NumArgs - 1 - I];
235 popArg(S, Arg: A);
236 }
237 }
238
239 // And in any case, remove the fixed parameters (the non-variadic ones)
240 // at the end.
241 S.Current->popArgs();
242}
243
244bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
245 if (!Ptr.isExtern())
246 return true;
247
248 if (Ptr.isInitialized())
249 return true;
250
251 if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
252 const auto *VD = Ptr.getDeclDesc()->asValueDecl();
253 diagnoseNonConstVariable(S, OpPC, VD);
254 }
255 return false;
256}
257
258bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
259 if (!Ptr.isUnknownSizeArray())
260 return true;
261 const SourceInfo &E = S.Current->getSource(PC: OpPC);
262 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
263 return false;
264}
265
266bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
267 AccessKinds AK) {
268 if (Ptr.isZero()) {
269 const auto &Src = S.Current->getSource(PC: OpPC);
270
271 if (Ptr.isField())
272 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
273 else
274 S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
275
276 return false;
277 }
278
279 if (!Ptr.isLive()) {
280 const auto &Src = S.Current->getSource(PC: OpPC);
281 bool IsTemp = Ptr.isTemporary();
282
283 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
284
285 if (IsTemp)
286 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
287 else
288 S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
289
290 return false;
291 }
292
293 return true;
294}
295
296bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
297 assert(Desc);
298
299 auto IsConstType = [&S](const VarDecl *VD) -> bool {
300 if (VD->isConstexpr())
301 return true;
302
303 QualType T = VD->getType();
304 if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
305 return T->isSignedIntegerOrEnumerationType() || T->isUnsignedIntegerOrEnumerationType();
306
307 if (T.isConstQualified())
308 return true;
309
310 if (const auto *RT = T->getAs<ReferenceType>())
311 return RT->getPointeeType().isConstQualified();
312
313 if (const auto *PT = T->getAs<PointerType>())
314 return PT->getPointeeType().isConstQualified();
315
316 return false;
317 };
318
319 if (const auto *D = Desc->asValueDecl()) {
320 if (const auto *VD = dyn_cast<VarDecl>(Val: D);
321 VD && VD->hasGlobalStorage() && !IsConstType(VD)) {
322 diagnoseNonConstVariable(S, OpPC, VD);
323 return S.inConstantContext();
324 }
325 }
326
327 return true;
328}
329
330static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
331 if (Ptr.isIntegralPointer())
332 return true;
333 return CheckConstant(S, OpPC, Desc: Ptr.getDeclDesc());
334}
335
336bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
337 CheckSubobjectKind CSK) {
338 if (!Ptr.isZero())
339 return true;
340 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
341 S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
342 return false;
343}
344
345bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
346 AccessKinds AK) {
347 if (!Ptr.isOnePastEnd())
348 return true;
349 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
350 S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
351 return false;
352}
353
354bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
355 CheckSubobjectKind CSK) {
356 if (!Ptr.isElementPastEnd())
357 return true;
358 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
359 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
360 return false;
361}
362
363bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
364 CheckSubobjectKind CSK) {
365 if (!Ptr.isOnePastEnd())
366 return true;
367
368 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
369 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
370 return false;
371}
372
373bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
374 assert(Ptr.isLive() && "Pointer is not live");
375 if (!Ptr.isConst())
376 return true;
377
378 // The This pointer is writable in constructors and destructors,
379 // even if isConst() returns true.
380 if (const Function *Func = S.Current->getFunction();
381 Func && (Func->isConstructor() || Func->isDestructor()) &&
382 Ptr.block() == S.Current->getThis().block()) {
383 return true;
384 }
385
386 if (!Ptr.isBlockPointer())
387 return false;
388
389 const QualType Ty = Ptr.getType();
390 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
391 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
392 return false;
393}
394
395bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
396 assert(Ptr.isLive() && "Pointer is not live");
397 if (!Ptr.isMutable()) {
398 return true;
399 }
400
401 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
402 const FieldDecl *Field = Ptr.getField();
403 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
404 S.Note(Field->getLocation(), diag::note_declared_at);
405 return false;
406}
407
408bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
409 AccessKinds AK) {
410 assert(Ptr.isLive());
411
412 if (Ptr.isInitialized())
413 return true;
414
415 if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
416 VD && VD->hasGlobalStorage()) {
417 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
418 if (VD->getAnyInitializer()) {
419 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
420 S.Note(VD->getLocation(), diag::note_declared_at);
421 } else {
422 diagnoseMissingInitializer(S, OpPC, VD);
423 }
424 return false;
425 }
426
427 if (!S.checkingPotentialConstantExpression()) {
428 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
429 << AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
430 }
431 return false;
432}
433
434bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
435 if (Ptr.isInitialized())
436 return true;
437
438 assert(S.getLangOpts().CPlusPlus);
439 const auto *VD = cast<VarDecl>(Val: Ptr.getDeclDesc()->asValueDecl());
440 if ((!VD->hasConstantInitialization() &&
441 VD->mightBeUsableInConstantExpressions(C: S.getCtx())) ||
442 (S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&
443 !VD->hasICEInitializer(Context: S.getCtx()))) {
444 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
445 S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
446 S.Note(VD->getLocation(), diag::note_declared_at);
447 }
448 return false;
449}
450
451bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
452 if (!CheckLive(S, OpPC, Ptr, AK: AK_Read))
453 return false;
454 if (!CheckConstant(S, OpPC, Ptr))
455 return false;
456
457 if (!CheckDummy(S, OpPC, Ptr))
458 return false;
459 if (!CheckExtern(S, OpPC, Ptr))
460 return false;
461 if (!CheckRange(S, OpPC, Ptr, AK: AK_Read))
462 return false;
463 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Read))
464 return false;
465 if (!CheckActive(S, OpPC, Ptr, AK: AK_Read))
466 return false;
467 if (!CheckTemporary(S, OpPC, Ptr, AK: AK_Read))
468 return false;
469 if (!CheckMutable(S, OpPC, Ptr))
470 return false;
471 return true;
472}
473
474bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
475 if (!CheckLive(S, OpPC, Ptr, AK: AK_Assign))
476 return false;
477 if (!CheckDummy(S, OpPC, Ptr))
478 return false;
479 if (!CheckExtern(S, OpPC, Ptr))
480 return false;
481 if (!CheckRange(S, OpPC, Ptr, AK: AK_Assign))
482 return false;
483 if (!CheckGlobal(S, OpPC, Ptr))
484 return false;
485 if (!CheckConst(S, OpPC, Ptr))
486 return false;
487 return true;
488}
489
490bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
491 if (!CheckLive(S, OpPC, Ptr, AK: AK_MemberCall))
492 return false;
493 if (!CheckExtern(S, OpPC, Ptr))
494 return false;
495 if (!CheckRange(S, OpPC, Ptr, AK: AK_MemberCall))
496 return false;
497 return true;
498}
499
500bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
501 if (!CheckLive(S, OpPC, Ptr, AK: AK_Assign))
502 return false;
503 if (!CheckRange(S, OpPC, Ptr, AK: AK_Assign))
504 return false;
505 return true;
506}
507
508bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
509
510 if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
511 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
512 S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
513 return false;
514 }
515
516 if (!F->isConstexpr()) {
517 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
518 if (S.getLangOpts().CPlusPlus11) {
519 const FunctionDecl *DiagDecl = F->getDecl();
520
521 // Invalid decls have been diagnosed before.
522 if (DiagDecl->isInvalidDecl())
523 return false;
524
525 // If this function is not constexpr because it is an inherited
526 // non-constexpr constructor, diagnose that directly.
527 const auto *CD = dyn_cast<CXXConstructorDecl>(Val: DiagDecl);
528 if (CD && CD->isInheritingConstructor()) {
529 const auto *Inherited = CD->getInheritedConstructor().getConstructor();
530 if (!Inherited->isConstexpr())
531 DiagDecl = CD = Inherited;
532 }
533
534 // FIXME: If DiagDecl is an implicitly-declared special member function
535 // or an inheriting constructor, we should be much more explicit about why
536 // it's not constexpr.
537 if (CD && CD->isInheritingConstructor()) {
538 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
539 << CD->getInheritedConstructor().getConstructor()->getParent();
540 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
541 } else {
542 // Don't emit anything if the function isn't defined and we're checking
543 // for a constant expression. It might be defined at the point we're
544 // actually calling it.
545 bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
546 if (!DiagDecl->isDefined() && !IsExtern &&
547 S.checkingPotentialConstantExpression())
548 return false;
549
550 // If the declaration is defined _and_ declared 'constexpr', the below
551 // diagnostic doesn't add anything useful.
552 if (DiagDecl->isDefined() && DiagDecl->isConstexpr())
553 return false;
554
555 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
556 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
557 S.Note(DiagDecl->getLocation(), diag::note_declared_at);
558 }
559 } else {
560 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
561 }
562 return false;
563 }
564
565 return true;
566}
567
568bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
569 if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
570 S.FFDiag(S.Current->getSource(OpPC),
571 diag::note_constexpr_depth_limit_exceeded)
572 << S.getLangOpts().ConstexprCallDepth;
573 return false;
574 }
575
576 return true;
577}
578
579bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
580 if (!This.isZero())
581 return true;
582
583 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
584
585 bool IsImplicit = false;
586 if (const auto *E = dyn_cast_if_present<CXXThisExpr>(Val: Loc.asExpr()))
587 IsImplicit = E->isImplicit();
588
589 if (S.getLangOpts().CPlusPlus11)
590 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
591 else
592 S.FFDiag(SI: Loc);
593
594 return false;
595}
596
597bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
598 if (!MD->isPureVirtual())
599 return true;
600 const SourceInfo &E = S.Current->getSource(PC: OpPC);
601 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
602 S.Note(MD->getLocation(), diag::note_declared_at);
603 return false;
604}
605
606bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
607 APFloat::opStatus Status) {
608 const SourceInfo &E = S.Current->getSource(PC: OpPC);
609
610 // [expr.pre]p4:
611 // If during the evaluation of an expression, the result is not
612 // mathematically defined [...], the behavior is undefined.
613 // FIXME: C++ rules require us to not conform to IEEE 754 here.
614 if (Result.isNan()) {
615 S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
616 << /*NaN=*/true << S.Current->getRange(OpPC);
617 return S.noteUndefinedBehavior();
618 }
619
620 // In a constant context, assume that any dynamic rounding mode or FP
621 // exception state matches the default floating-point environment.
622 if (S.inConstantContext())
623 return true;
624
625 FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(LO: S.Ctx.getLangOpts());
626
627 if ((Status & APFloat::opInexact) &&
628 FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
629 // Inexact result means that it depends on rounding mode. If the requested
630 // mode is dynamic, the evaluation cannot be made in compile time.
631 S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
632 return false;
633 }
634
635 if ((Status != APFloat::opOK) &&
636 (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
637 FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
638 FPO.getAllowFEnvAccess())) {
639 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
640 return false;
641 }
642
643 if ((Status & APFloat::opStatus::opInvalidOp) &&
644 FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
645 // There is no usefully definable result.
646 S.FFDiag(SI: E);
647 return false;
648 }
649
650 return true;
651}
652
653/// We aleady know the given DeclRefExpr is invalid for some reason,
654/// now figure out why and print appropriate diagnostics.
655bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
656 const ValueDecl *D = DR->getDecl();
657 return diagnoseUnknownDecl(S, OpPC, D);
658}
659
660bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
661 if (!Ptr.isDummy())
662 return true;
663
664 const Descriptor *Desc = Ptr.getDeclDesc();
665 const ValueDecl *D = Desc->asValueDecl();
666 if (!D)
667 return false;
668
669 return diagnoseUnknownDecl(S, OpPC, D);
670}
671
672bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
673 const CallExpr *CE, unsigned ArgSize) {
674 auto Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());
675 auto NonNullArgs = collectNonNullArgs(F: F->getDecl(), Args);
676 unsigned Offset = 0;
677 unsigned Index = 0;
678 for (const Expr *Arg : Args) {
679 if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
680 const Pointer &ArgPtr = S.Stk.peek<Pointer>(Offset: ArgSize - Offset);
681 if (ArgPtr.isZero()) {
682 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
683 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
684 return false;
685 }
686 }
687
688 Offset += align(Size: primSize(Type: S.Ctx.classify(E: Arg).value_or(u: PT_Ptr)));
689 ++Index;
690 }
691 return true;
692}
693
694bool Interpret(InterpState &S, APValue &Result) {
695 // The current stack frame when we started Interpret().
696 // This is being used by the ops to determine wheter
697 // to return from this function and thus terminate
698 // interpretation.
699 const InterpFrame *StartFrame = S.Current;
700 assert(!S.Current->isRoot());
701 CodePtr PC = S.Current->getPC();
702
703 // Empty program.
704 if (!PC)
705 return true;
706
707 for (;;) {
708 auto Op = PC.read<Opcode>();
709 CodePtr OpPC = PC;
710
711 switch (Op) {
712#define GET_INTERP
713#include "Opcodes.inc"
714#undef GET_INTERP
715 }
716 }
717}
718
719} // namespace interp
720} // namespace clang
721

source code of clang/lib/AST/Interp/Interp.cpp