Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp
35291 views
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
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
42
static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
43
PC += Offset;
44
return true;
45
}
46
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
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
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);
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
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
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
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
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 {
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
780
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
781
const ValueDecl *D = DR->getDecl();
782
return diagnoseUnknownDecl(S, OpPC, D);
783
}
784
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
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.
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
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
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
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
964