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