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