xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp (revision 415efcecd8b80f68e76376ef2b854cb6f5c84b5a)
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/DeclObjC.h"
22 #include "clang/AST/Expr.h"
23 #include "clang/AST/ExprCXX.h"
24 #include "llvm/ADT/APSInt.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include <limits>
27 #include <vector>
28 
29 using namespace clang;
30 
31 using namespace clang;
32 using namespace clang::interp;
33 
RetValue(InterpState & S,CodePtr & Pt,APValue & Result)34 static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
35   llvm::report_fatal_error("Interpreter cannot return values");
36 }
37 
38 //===----------------------------------------------------------------------===//
39 // Jmp, Jt, Jf
40 //===----------------------------------------------------------------------===//
41 
Jmp(InterpState & S,CodePtr & PC,int32_t Offset)42 static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
43   PC += Offset;
44   return true;
45 }
46 
Jt(InterpState & S,CodePtr & PC,int32_t Offset)47 static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
48   if (S.Stk.pop<bool>()) {
49     PC += Offset;
50   }
51   return true;
52 }
53 
Jf(InterpState & S,CodePtr & PC,int32_t Offset)54 static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
55   if (!S.Stk.pop<bool>()) {
56     PC += Offset;
57   }
58   return true;
59 }
60 
diagnoseMissingInitializer(InterpState & S,CodePtr OpPC,const ValueDecl * VD)61 static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,
62                                        const ValueDecl *VD) {
63   const SourceInfo &E = S.Current->getSource(OpPC);
64   S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
65   S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
66 }
67 
68 static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
69                                      const ValueDecl *VD);
diagnoseUnknownDecl(InterpState & S,CodePtr OpPC,const ValueDecl * D)70 static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
71                                 const ValueDecl *D) {
72   const SourceInfo &E = S.Current->getSource(OpPC);
73 
74   if (isa<ParmVarDecl>(D)) {
75     if (S.getLangOpts().CPlusPlus11) {
76       S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
77       S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
78     } else {
79       S.FFDiag(E);
80     }
81     return false;
82   }
83 
84   if (!D->getType().isConstQualified())
85     diagnoseNonConstVariable(S, OpPC, D);
86   else if (const auto *VD = dyn_cast<VarDecl>(D);
87            VD && !VD->getAnyInitializer())
88     diagnoseMissingInitializer(S, OpPC, VD);
89 
90   return false;
91 }
92 
diagnoseNonConstVariable(InterpState & S,CodePtr OpPC,const ValueDecl * VD)93 static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
94                                      const ValueDecl *VD) {
95   if (!S.getLangOpts().CPlusPlus)
96     return;
97 
98   const SourceInfo &Loc = S.Current->getSource(OpPC);
99   if (const auto *VarD = dyn_cast<VarDecl>(VD);
100       VarD && VarD->getType().isConstQualified() &&
101       !VarD->getAnyInitializer()) {
102     diagnoseMissingInitializer(S, OpPC, VD);
103     return;
104   }
105 
106   // Rather random, but this is to match the diagnostic output of the current
107   // interpreter.
108   if (isa<ObjCIvarDecl>(VD))
109     return;
110 
111   if (VD->getType()->isIntegralOrEnumerationType()) {
112     S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
113     S.Note(VD->getLocation(), diag::note_declared_at);
114     return;
115   }
116 
117   S.FFDiag(Loc,
118            S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
119                                        : diag::note_constexpr_ltor_non_integral,
120            1)
121       << VD << VD->getType();
122   S.Note(VD->getLocation(), diag::note_declared_at);
123 }
124 
CheckActive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)125 static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
126                         AccessKinds AK) {
127   if (Ptr.isActive())
128     return true;
129 
130   // Get the inactive field descriptor.
131   const FieldDecl *InactiveField = Ptr.getField();
132 
133   // Walk up the pointer chain to find the union which is not active.
134   Pointer U = Ptr.getBase();
135   while (!U.isActive()) {
136     U = U.getBase();
137   }
138 
139   // Find the active field of the union.
140   const Record *R = U.getRecord();
141   assert(R && R->isUnion() && "Not a union");
142   const FieldDecl *ActiveField = nullptr;
143   for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
144     const Pointer &Field = U.atField(R->getField(I)->Offset);
145     if (Field.isActive()) {
146       ActiveField = Field.getField();
147       break;
148     }
149   }
150 
151   const SourceInfo &Loc = S.Current->getSource(OpPC);
152   S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
153       << AK << InactiveField << !ActiveField << ActiveField;
154   return false;
155 }
156 
CheckTemporary(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)157 static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
158                            AccessKinds AK) {
159   if (auto ID = Ptr.getDeclID()) {
160     if (!Ptr.isStaticTemporary())
161       return true;
162 
163     if (Ptr.getDeclDesc()->getType().isConstQualified())
164       return true;
165 
166     if (S.P.getCurrentDecl() == ID)
167       return true;
168 
169     const SourceInfo &E = S.Current->getSource(OpPC);
170     S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
171     S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
172     return false;
173   }
174   return true;
175 }
176 
CheckGlobal(InterpState & S,CodePtr OpPC,const Pointer & Ptr)177 static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
178   if (auto ID = Ptr.getDeclID()) {
179     if (!Ptr.isStatic())
180       return true;
181 
182     if (S.P.getCurrentDecl() == ID)
183       return true;
184 
185     S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
186     return false;
187   }
188   return true;
189 }
190 
191 namespace clang {
192 namespace interp {
popArg(InterpState & S,const Expr * Arg)193 static void popArg(InterpState &S, const Expr *Arg) {
194   PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);
195   TYPE_SWITCH(Ty, S.Stk.discard<T>());
196 }
197 
cleanupAfterFunctionCall(InterpState & S,CodePtr OpPC)198 void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
199   assert(S.Current);
200   const Function *CurFunc = S.Current->getFunction();
201   assert(CurFunc);
202 
203   if (CurFunc->isUnevaluatedBuiltin())
204     return;
205 
206   // Some builtin functions require us to only look at the call site, since
207   // the classified parameter types do not match.
208   if (CurFunc->isBuiltin()) {
209     const auto *CE =
210         cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
211     for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
212       const Expr *A = CE->getArg(I);
213       popArg(S, A);
214     }
215     return;
216   }
217 
218   if (S.Current->Caller && CurFunc->isVariadic()) {
219     // CallExpr we're look for is at the return PC of the current function, i.e.
220     // in the caller.
221     // This code path should be executed very rarely.
222     unsigned NumVarArgs;
223     const Expr *const *Args = nullptr;
224     unsigned NumArgs = 0;
225     const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());
226     if (const auto *CE = dyn_cast<CallExpr>(CallSite)) {
227       Args = CE->getArgs();
228       NumArgs = CE->getNumArgs();
229     } else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
230       Args = CE->getArgs();
231       NumArgs = CE->getNumArgs();
232     } else
233       assert(false && "Can't get arguments from that expression type");
234 
235     assert(NumArgs >= CurFunc->getNumWrittenParams());
236     NumVarArgs = NumArgs - CurFunc->getNumWrittenParams();
237     for (unsigned I = 0; I != NumVarArgs; ++I) {
238       const Expr *A = Args[NumArgs - 1 - I];
239       popArg(S, A);
240     }
241   }
242 
243   // And in any case, remove the fixed parameters (the non-variadic ones)
244   // at the end.
245   S.Current->popArgs();
246 }
247 
CheckExtern(InterpState & S,CodePtr OpPC,const Pointer & Ptr)248 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
249   if (!Ptr.isExtern())
250     return true;
251 
252   if (Ptr.isInitialized() ||
253       (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))
254     return true;
255 
256   if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
257     const auto *VD = Ptr.getDeclDesc()->asValueDecl();
258     diagnoseNonConstVariable(S, OpPC, VD);
259   }
260   return false;
261 }
262 
CheckArray(InterpState & S,CodePtr OpPC,const Pointer & Ptr)263 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
264   if (!Ptr.isUnknownSizeArray())
265     return true;
266   const SourceInfo &E = S.Current->getSource(OpPC);
267   S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
268   return false;
269 }
270 
CheckLive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)271 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
272                AccessKinds AK) {
273   if (Ptr.isZero()) {
274     const auto &Src = S.Current->getSource(OpPC);
275 
276     if (Ptr.isField())
277       S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
278     else
279       S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
280 
281     return false;
282   }
283 
284   if (!Ptr.isLive()) {
285     const auto &Src = S.Current->getSource(OpPC);
286     bool IsTemp = Ptr.isTemporary();
287 
288     S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
289 
290     if (IsTemp)
291       S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
292     else
293       S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
294 
295     return false;
296   }
297 
298   return true;
299 }
300 
CheckConstant(InterpState & S,CodePtr OpPC,const Descriptor * Desc)301 bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
302   assert(Desc);
303 
304   auto IsConstType = [&S](const VarDecl *VD) -> bool {
305     if (VD->isConstexpr())
306       return true;
307 
308     QualType T = VD->getType();
309     if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
310       return (T->isSignedIntegerOrEnumerationType() ||
311               T->isUnsignedIntegerOrEnumerationType()) &&
312              T.isConstQualified();
313 
314     if (T.isConstQualified())
315       return true;
316 
317     if (const auto *RT = T->getAs<ReferenceType>())
318       return RT->getPointeeType().isConstQualified();
319 
320     if (const auto *PT = T->getAs<PointerType>())
321       return PT->getPointeeType().isConstQualified();
322 
323     return false;
324   };
325 
326   if (const auto *D = Desc->asVarDecl();
327       D && D->hasGlobalStorage() && D != S.EvaluatingDecl && !IsConstType(D)) {
328     diagnoseNonConstVariable(S, OpPC, D);
329     return S.inConstantContext();
330   }
331 
332   return true;
333 }
334 
CheckConstant(InterpState & S,CodePtr OpPC,const Pointer & Ptr)335 static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
336   if (Ptr.isIntegralPointer())
337     return true;
338   return CheckConstant(S, OpPC, Ptr.getDeclDesc());
339 }
340 
CheckNull(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)341 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
342                CheckSubobjectKind CSK) {
343   if (!Ptr.isZero())
344     return true;
345   const SourceInfo &Loc = S.Current->getSource(OpPC);
346   S.FFDiag(Loc, diag::note_constexpr_null_subobject)
347       << CSK << S.Current->getRange(OpPC);
348 
349   return false;
350 }
351 
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)352 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
353                 AccessKinds AK) {
354   if (!Ptr.isOnePastEnd())
355     return true;
356   const SourceInfo &Loc = S.Current->getSource(OpPC);
357   S.FFDiag(Loc, diag::note_constexpr_access_past_end)
358       << AK << S.Current->getRange(OpPC);
359   return false;
360 }
361 
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)362 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
363                 CheckSubobjectKind CSK) {
364   if (!Ptr.isElementPastEnd())
365     return true;
366   const SourceInfo &Loc = S.Current->getSource(OpPC);
367   S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
368       << CSK << S.Current->getRange(OpPC);
369   return false;
370 }
371 
CheckSubobject(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)372 bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
373                     CheckSubobjectKind CSK) {
374   if (!Ptr.isOnePastEnd())
375     return true;
376 
377   const SourceInfo &Loc = S.Current->getSource(OpPC);
378   S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
379       << CSK << S.Current->getRange(OpPC);
380   return false;
381 }
382 
CheckDowncast(InterpState & S,CodePtr OpPC,const Pointer & Ptr,uint32_t Offset)383 bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
384                    uint32_t Offset) {
385   uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();
386   uint32_t PtrOffset = Ptr.getByteOffset();
387 
388   // We subtract Offset from PtrOffset. The result must be at least
389   // MinOffset.
390   if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
391     return true;
392 
393   const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
394   QualType TargetQT = E->getType()->getPointeeType();
395   QualType MostDerivedQT = Ptr.getDeclPtr().getType();
396 
397   S.CCEDiag(E, diag::note_constexpr_invalid_downcast)
398       << MostDerivedQT << TargetQT;
399 
400   return false;
401 }
402 
CheckConst(InterpState & S,CodePtr OpPC,const Pointer & Ptr)403 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
404   assert(Ptr.isLive() && "Pointer is not live");
405   if (!Ptr.isConst() || Ptr.isMutable())
406     return true;
407 
408   // The This pointer is writable in constructors and destructors,
409   // even if isConst() returns true.
410   // TODO(perf): We could be hitting this code path quite a lot in complex
411   // constructors. Is there a better way to do this?
412   if (S.Current->getFunction()) {
413     for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
414       if (const Function *Func = Frame->getFunction();
415           Func && (Func->isConstructor() || Func->isDestructor()) &&
416           Ptr.block() == Frame->getThis().block()) {
417         return true;
418       }
419     }
420   }
421 
422   if (!Ptr.isBlockPointer())
423     return false;
424 
425   const QualType Ty = Ptr.getType();
426   const SourceInfo &Loc = S.Current->getSource(OpPC);
427   S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
428   return false;
429 }
430 
CheckMutable(InterpState & S,CodePtr OpPC,const Pointer & Ptr)431 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
432   assert(Ptr.isLive() && "Pointer is not live");
433   if (!Ptr.isMutable())
434     return true;
435 
436   // In C++14 onwards, it is permitted to read a mutable member whose
437   // lifetime began within the evaluation.
438   if (S.getLangOpts().CPlusPlus14 &&
439       Ptr.block()->getEvalID() == S.Ctx.getEvalID())
440     return true;
441 
442   const SourceInfo &Loc = S.Current->getSource(OpPC);
443   const FieldDecl *Field = Ptr.getField();
444   S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
445   S.Note(Field->getLocation(), diag::note_declared_at);
446   return false;
447 }
448 
CheckVolatile(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)449 bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
450                    AccessKinds AK) {
451   assert(Ptr.isLive());
452 
453   // FIXME: This check here might be kinda expensive. Maybe it would be better
454   // to have another field in InlineDescriptor for this?
455   if (!Ptr.isBlockPointer())
456     return true;
457 
458   QualType PtrType = Ptr.getType();
459   if (!PtrType.isVolatileQualified())
460     return true;
461 
462   const SourceInfo &Loc = S.Current->getSource(OpPC);
463   if (S.getLangOpts().CPlusPlus)
464     S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;
465   else
466     S.FFDiag(Loc);
467   return false;
468 }
469 
CheckInitialized(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)470 bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
471                       AccessKinds AK) {
472   assert(Ptr.isLive());
473 
474   if (Ptr.isInitialized())
475     return true;
476 
477   if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
478       VD && VD->hasGlobalStorage()) {
479     const SourceInfo &Loc = S.Current->getSource(OpPC);
480     if (VD->getAnyInitializer()) {
481       S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
482       S.Note(VD->getLocation(), diag::note_declared_at);
483     } else {
484       diagnoseMissingInitializer(S, OpPC, VD);
485     }
486     return false;
487   }
488 
489   if (!S.checkingPotentialConstantExpression()) {
490     S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
491         << AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
492   }
493   return false;
494 }
495 
CheckGlobalInitialized(InterpState & S,CodePtr OpPC,const Pointer & Ptr)496 bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
497   if (Ptr.isInitialized())
498     return true;
499 
500   assert(S.getLangOpts().CPlusPlus);
501   const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());
502   if ((!VD->hasConstantInitialization() &&
503        VD->mightBeUsableInConstantExpressions(S.getCtx())) ||
504       (S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&
505        !VD->hasICEInitializer(S.getCtx()))) {
506     const SourceInfo &Loc = S.Current->getSource(OpPC);
507     S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
508     S.Note(VD->getLocation(), diag::note_declared_at);
509   }
510   return false;
511 }
512 
CheckLoad(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)513 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
514                AccessKinds AK) {
515   if (!CheckLive(S, OpPC, Ptr, AK))
516     return false;
517   if (!CheckConstant(S, OpPC, Ptr))
518     return false;
519 
520   if (!CheckDummy(S, OpPC, Ptr, AK))
521     return false;
522   if (!CheckExtern(S, OpPC, Ptr))
523     return false;
524   if (!CheckRange(S, OpPC, Ptr, AK))
525     return false;
526   if (!CheckActive(S, OpPC, Ptr, AK))
527     return false;
528   if (!CheckInitialized(S, OpPC, Ptr, AK))
529     return false;
530   if (!CheckTemporary(S, OpPC, Ptr, AK))
531     return false;
532   if (!CheckMutable(S, OpPC, Ptr))
533     return false;
534   if (!CheckVolatile(S, OpPC, Ptr, AK))
535     return false;
536   return true;
537 }
538 
CheckStore(InterpState & S,CodePtr OpPC,const Pointer & Ptr)539 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
540   if (!CheckLive(S, OpPC, Ptr, AK_Assign))
541     return false;
542   if (!CheckDummy(S, OpPC, Ptr, AK_Assign))
543     return false;
544   if (!CheckExtern(S, OpPC, Ptr))
545     return false;
546   if (!CheckRange(S, OpPC, Ptr, AK_Assign))
547     return false;
548   if (!CheckGlobal(S, OpPC, Ptr))
549     return false;
550   if (!CheckConst(S, OpPC, Ptr))
551     return false;
552   return true;
553 }
554 
CheckInvoke(InterpState & S,CodePtr OpPC,const Pointer & Ptr)555 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
556   if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
557     return false;
558   if (!Ptr.isDummy()) {
559     if (!CheckExtern(S, OpPC, Ptr))
560       return false;
561     if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
562       return false;
563   }
564   return true;
565 }
566 
CheckInit(InterpState & S,CodePtr OpPC,const Pointer & Ptr)567 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
568   if (!CheckLive(S, OpPC, Ptr, AK_Assign))
569     return false;
570   if (!CheckRange(S, OpPC, Ptr, AK_Assign))
571     return false;
572   return true;
573 }
574 
CheckCallable(InterpState & S,CodePtr OpPC,const Function * F)575 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
576 
577   if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
578     const SourceLocation &Loc = S.Current->getLocation(OpPC);
579     S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
580     return false;
581   }
582 
583   if (F->isConstexpr() && F->hasBody() &&
584       (F->getDecl()->isConstexpr() || F->getDecl()->hasAttr<MSConstexprAttr>()))
585     return true;
586 
587   // Implicitly constexpr.
588   if (F->isLambdaStaticInvoker())
589     return true;
590 
591   const SourceLocation &Loc = S.Current->getLocation(OpPC);
592   if (S.getLangOpts().CPlusPlus11) {
593     const FunctionDecl *DiagDecl = F->getDecl();
594 
595     // Invalid decls have been diagnosed before.
596     if (DiagDecl->isInvalidDecl())
597       return false;
598 
599     // If this function is not constexpr because it is an inherited
600     // non-constexpr constructor, diagnose that directly.
601     const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
602     if (CD && CD->isInheritingConstructor()) {
603       const auto *Inherited = CD->getInheritedConstructor().getConstructor();
604       if (!Inherited->isConstexpr())
605         DiagDecl = CD = Inherited;
606     }
607 
608     // FIXME: If DiagDecl is an implicitly-declared special member function
609     // or an inheriting constructor, we should be much more explicit about why
610     // it's not constexpr.
611     if (CD && CD->isInheritingConstructor()) {
612       S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
613           << CD->getInheritedConstructor().getConstructor()->getParent();
614       S.Note(DiagDecl->getLocation(), diag::note_declared_at);
615     } else {
616       // Don't emit anything if the function isn't defined and we're checking
617       // for a constant expression. It might be defined at the point we're
618       // actually calling it.
619       bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
620       if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() &&
621           S.checkingPotentialConstantExpression())
622         return false;
623 
624       // If the declaration is defined, declared 'constexpr' _and_ has a body,
625       // the below diagnostic doesn't add anything useful.
626       if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
627           DiagDecl->hasBody())
628         return false;
629 
630       S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
631           << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
632       S.Note(DiagDecl->getLocation(), diag::note_declared_at);
633     }
634   } else {
635     S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
636   }
637 
638   return false;
639 }
640 
CheckCallDepth(InterpState & S,CodePtr OpPC)641 bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
642   if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
643     S.FFDiag(S.Current->getSource(OpPC),
644              diag::note_constexpr_depth_limit_exceeded)
645         << S.getLangOpts().ConstexprCallDepth;
646     return false;
647   }
648 
649   return true;
650 }
651 
CheckThis(InterpState & S,CodePtr OpPC,const Pointer & This)652 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
653   if (!This.isZero())
654     return true;
655 
656   const SourceInfo &Loc = S.Current->getSource(OpPC);
657 
658   bool IsImplicit = false;
659   if (const auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.asExpr()))
660     IsImplicit = E->isImplicit();
661 
662   if (S.getLangOpts().CPlusPlus11)
663     S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
664   else
665     S.FFDiag(Loc);
666 
667   return false;
668 }
669 
CheckPure(InterpState & S,CodePtr OpPC,const CXXMethodDecl * MD)670 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
671   if (!MD->isPureVirtual())
672     return true;
673   const SourceInfo &E = S.Current->getSource(OpPC);
674   S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
675   S.Note(MD->getLocation(), diag::note_declared_at);
676   return false;
677 }
678 
CheckFloatResult(InterpState & S,CodePtr OpPC,const Floating & Result,APFloat::opStatus Status)679 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
680                       APFloat::opStatus Status) {
681   const SourceInfo &E = S.Current->getSource(OpPC);
682 
683   // [expr.pre]p4:
684   //   If during the evaluation of an expression, the result is not
685   //   mathematically defined [...], the behavior is undefined.
686   // FIXME: C++ rules require us to not conform to IEEE 754 here.
687   if (Result.isNan()) {
688     S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
689         << /*NaN=*/true << S.Current->getRange(OpPC);
690     return S.noteUndefinedBehavior();
691   }
692 
693   // In a constant context, assume that any dynamic rounding mode or FP
694   // exception state matches the default floating-point environment.
695   if (S.inConstantContext())
696     return true;
697 
698   FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts());
699 
700   if ((Status & APFloat::opInexact) &&
701       FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
702     // Inexact result means that it depends on rounding mode. If the requested
703     // mode is dynamic, the evaluation cannot be made in compile time.
704     S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
705     return false;
706   }
707 
708   if ((Status != APFloat::opOK) &&
709       (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
710        FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
711        FPO.getAllowFEnvAccess())) {
712     S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
713     return false;
714   }
715 
716   if ((Status & APFloat::opStatus::opInvalidOp) &&
717       FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
718     // There is no usefully definable result.
719     S.FFDiag(E);
720     return false;
721   }
722 
723   return true;
724 }
725 
CheckDynamicMemoryAllocation(InterpState & S,CodePtr OpPC)726 bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) {
727   if (S.getLangOpts().CPlusPlus20)
728     return true;
729 
730   const SourceInfo &E = S.Current->getSource(OpPC);
731   S.CCEDiag(E, diag::note_constexpr_new);
732   return true;
733 }
734 
CheckNewDeleteForms(InterpState & S,CodePtr OpPC,bool NewWasArray,bool DeleteIsArray,const Descriptor * D,const Expr * NewExpr)735 bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
736                          bool DeleteIsArray, const Descriptor *D,
737                          const Expr *NewExpr) {
738   if (NewWasArray == DeleteIsArray)
739     return true;
740 
741   QualType TypeToDiagnose;
742   // We need to shuffle things around a bit here to get a better diagnostic,
743   // because the expression we allocated the block for was of type int*,
744   // but we want to get the array size right.
745   if (D->isArray()) {
746     QualType ElemQT = D->getType()->getPointeeType();
747     TypeToDiagnose = S.getCtx().getConstantArrayType(
748         ElemQT, APInt(64, static_cast<uint64_t>(D->getNumElems()), false),
749         nullptr, ArraySizeModifier::Normal, 0);
750   } else
751     TypeToDiagnose = D->getType()->getPointeeType();
752 
753   const SourceInfo &E = S.Current->getSource(OpPC);
754   S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
755       << DeleteIsArray << 0 << TypeToDiagnose;
756   S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
757       << NewExpr->getSourceRange();
758   return false;
759 }
760 
CheckDeleteSource(InterpState & S,CodePtr OpPC,const Expr * Source,const Pointer & Ptr)761 bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
762                        const Pointer &Ptr) {
763   if (Source && isa<CXXNewExpr>(Source))
764     return true;
765 
766   // Whatever this is, we didn't heap allocate it.
767   const SourceInfo &Loc = S.Current->getSource(OpPC);
768   S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
769       << Ptr.toDiagnosticString(S.getCtx());
770 
771   if (Ptr.isTemporary())
772     S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
773   else
774     S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
775   return false;
776 }
777 
778 /// We aleady know the given DeclRefExpr is invalid for some reason,
779 /// now figure out why and print appropriate diagnostics.
CheckDeclRef(InterpState & S,CodePtr OpPC,const DeclRefExpr * DR)780 bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
781   const ValueDecl *D = DR->getDecl();
782   return diagnoseUnknownDecl(S, OpPC, D);
783 }
784 
CheckDummy(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)785 bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
786                 AccessKinds AK) {
787   if (!Ptr.isDummy())
788     return true;
789 
790   const Descriptor *Desc = Ptr.getDeclDesc();
791   const ValueDecl *D = Desc->asValueDecl();
792   if (!D)
793     return false;
794 
795   if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)
796     return diagnoseUnknownDecl(S, OpPC, D);
797 
798   assert(AK == AK_Assign);
799   if (S.getLangOpts().CPlusPlus11) {
800     const SourceInfo &E = S.Current->getSource(OpPC);
801     S.FFDiag(E, diag::note_constexpr_modify_global);
802   }
803   return false;
804 }
805 
CheckNonNullArgs(InterpState & S,CodePtr OpPC,const Function * F,const CallExpr * CE,unsigned ArgSize)806 bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
807                       const CallExpr *CE, unsigned ArgSize) {
808   auto Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());
809   auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);
810   unsigned Offset = 0;
811   unsigned Index = 0;
812   for (const Expr *Arg : Args) {
813     if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
814       const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);
815       if (ArgPtr.isZero()) {
816         const SourceLocation &Loc = S.Current->getLocation(OpPC);
817         S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
818         return false;
819       }
820     }
821 
822     Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));
823     ++Index;
824   }
825   return true;
826 }
827 
828 // FIXME: This is similar to code we already have in Compiler.cpp.
829 // I think it makes sense to instead add the field and base destruction stuff
830 // to the destructor Function itself. Then destroying a record would really
831 // _just_ be calling its destructor. That would also help with the diagnostic
832 // difference when the destructor or a field/base fails.
runRecordDestructor(InterpState & S,CodePtr OpPC,const Pointer & BasePtr,const Descriptor * Desc)833 static bool runRecordDestructor(InterpState &S, CodePtr OpPC,
834                                 const Pointer &BasePtr,
835                                 const Descriptor *Desc) {
836   assert(Desc->isRecord());
837   const Record *R = Desc->ElemRecord;
838   assert(R);
839 
840   // Fields.
841   for (const Record::Field &Field : llvm::reverse(R->fields())) {
842     const Descriptor *D = Field.Desc;
843     if (D->isRecord()) {
844       if (!runRecordDestructor(S, OpPC, BasePtr.atField(Field.Offset), D))
845         return false;
846     } else if (D->isCompositeArray()) {
847       const Descriptor *ElemDesc = Desc->ElemDesc;
848       assert(ElemDesc->isRecord());
849       for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
850         if (!runRecordDestructor(S, OpPC, BasePtr.atIndex(I).narrow(),
851                                  ElemDesc))
852           return false;
853       }
854     }
855   }
856 
857   // Destructor of this record.
858   if (const CXXDestructorDecl *Dtor = R->getDestructor();
859       Dtor && !Dtor->isTrivial()) {
860     const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
861     if (!DtorFunc)
862       return false;
863 
864     S.Stk.push<Pointer>(BasePtr);
865     if (!Call(S, OpPC, DtorFunc, 0))
866       return false;
867   }
868 
869   // Bases.
870   for (const Record::Base &Base : llvm::reverse(R->bases())) {
871     if (!runRecordDestructor(S, OpPC, BasePtr.atField(Base.Offset), Base.Desc))
872       return false;
873   }
874 
875   return true;
876 }
877 
RunDestructors(InterpState & S,CodePtr OpPC,const Block * B)878 bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
879   assert(B);
880   const Descriptor *Desc = B->getDescriptor();
881 
882   if (Desc->isPrimitive() || Desc->isPrimitiveArray())
883     return true;
884 
885   assert(Desc->isRecord() || Desc->isCompositeArray());
886 
887   if (Desc->isCompositeArray()) {
888     const Descriptor *ElemDesc = Desc->ElemDesc;
889     assert(ElemDesc->isRecord());
890 
891     Pointer RP(const_cast<Block *>(B));
892     for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
893       if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc))
894         return false;
895     }
896     return true;
897   }
898 
899   assert(Desc->isRecord());
900   return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);
901 }
902 
diagnoseEnumValue(InterpState & S,CodePtr OpPC,const EnumDecl * ED,const APSInt & Value)903 void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
904                        const APSInt &Value) {
905   llvm::APInt Min;
906   llvm::APInt Max;
907 
908   if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())
909     return;
910 
911   ED->getValueRange(Max, Min);
912   --Max;
913 
914   if (ED->getNumNegativeBits() &&
915       (Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {
916     const SourceLocation &Loc = S.Current->getLocation(OpPC);
917     S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range)
918         << llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()
919         << ED;
920   } else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {
921     const SourceLocation &Loc = S.Current->getLocation(OpPC);
922     S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range)
923         << llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()
924         << ED;
925   }
926 }
927 
928 // https://github.com/llvm/llvm-project/issues/102513
929 #if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG)
930 #pragma optimize("", off)
931 #endif
Interpret(InterpState & S,APValue & Result)932 bool Interpret(InterpState &S, APValue &Result) {
933   // The current stack frame when we started Interpret().
934   // This is being used by the ops to determine wheter
935   // to return from this function and thus terminate
936   // interpretation.
937   const InterpFrame *StartFrame = S.Current;
938   assert(!S.Current->isRoot());
939   CodePtr PC = S.Current->getPC();
940 
941   // Empty program.
942   if (!PC)
943     return true;
944 
945   for (;;) {
946     auto Op = PC.read<Opcode>();
947     CodePtr OpPC = PC;
948 
949     switch (Op) {
950 #define GET_INTERP
951 #include "Opcodes.inc"
952 #undef GET_INTERP
953     }
954   }
955 }
956 // https://github.com/llvm/llvm-project/issues/102513
957 #if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG)
958 #pragma optimize("", on)
959 #endif
960 
961 } // namespace interp
962 } // namespace clang
963