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