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