Coverage Report

Created: 2024-01-17 10:31

/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