Coverage Report

Created: 2020-03-31 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/Interp.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- InterpState.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
//===----------------------------------------------------------------------===//
30
// Ret
31
//===----------------------------------------------------------------------===//
32
33
template <PrimType Name, class T = typename PrimConv<Name>::T>
34
0
static bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
35
0
  S.CallStackDepth--;
36
0
  const T &Ret = S.Stk.pop<T>();
37
0
38
0
  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
39
0
  if (!S.checkingPotentialConstantExpression())
40
0
    S.Current->popArgs();
41
0
42
0
  if (InterpFrame *Caller = S.Current->Caller) {
43
0
    PC = S.Current->getRetPC();
44
0
    delete S.Current;
45
0
    S.Current = Caller;
46
0
    S.Stk.push<T>(Ret);
47
0
  } else {
48
0
    delete S.Current;
49
0
    S.Current = nullptr;
50
0
    if (!ReturnValue<T>(Ret, Result))
51
0
      return false;
52
0
  }
53
0
  return true;
54
0
}
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)0, clang::interp::Integral<8u, true> >(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)1, clang::interp::Integral<8u, false> >(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)2, clang::interp::Integral<16u, true> >(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)3, clang::interp::Integral<16u, false> >(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)4, clang::interp::Integral<32u, true> >(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)5, clang::interp::Integral<32u, false> >(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)6, clang::interp::Integral<64u, true> >(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)7, clang::interp::Integral<64u, false> >(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)8, clang::interp::Boolean>(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
Unexecuted instantiation: Interp.cpp:bool Ret<(clang::interp::PrimType)9, clang::interp::Pointer>(clang::interp::InterpState&, clang::interp::CodePtr&, clang::APValue&)
55
56
0
static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
57
0
  S.CallStackDepth--;
58
0
59
0
  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
60
0
  if (!S.checkingPotentialConstantExpression())
61
0
    S.Current->popArgs();
62
0
63
0
  if (InterpFrame *Caller = S.Current->Caller) {
64
0
    PC = S.Current->getRetPC();
65
0
    delete S.Current;
66
0
    S.Current = Caller;
67
0
  } else {
68
0
    delete S.Current;
69
0
    S.Current = nullptr;
70
0
  }
71
0
  return true;
72
0
}
73
74
0
static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
75
0
  llvm::report_fatal_error("Interpreter cannot return values");
76
0
}
77
78
//===----------------------------------------------------------------------===//
79
// Jmp, Jt, Jf
80
//===----------------------------------------------------------------------===//
81
82
0
static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
83
0
  PC += Offset;
84
0
  return true;
85
0
}
86
87
0
static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
88
0
  if (S.Stk.pop<bool>()) {
89
0
    PC += Offset;
90
0
  }
91
0
  return true;
92
0
}
93
94
0
static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
95
0
  if (!S.Stk.pop<bool>()) {
96
0
    PC += Offset;
97
0
  }
98
0
  return true;
99
0
}
100
101
static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
102
0
                             AccessKinds AK) {
103
0
  if (Ptr.isInitialized())
104
0
    return true;
105
0
  if (!S.checkingPotentialConstantExpression()) {
106
0
    const SourceInfo &Loc = S.Current->getSource(OpPC);
107
0
    S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
108
0
  }
109
0
  return false;
110
0
}
111
112
static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
113
0
                        AccessKinds AK) {
114
0
  if (Ptr.isActive())
115
0
    return true;
116
0
117
0
  // Get the inactive field descriptor.
118
0
  const FieldDecl *InactiveField = Ptr.getField();
119
0
120
0
  // Walk up the pointer chain to find the union which is not active.
121
0
  Pointer U = Ptr.getBase();
122
0
  while (!U.isActive()) {
123
0
    U = U.getBase();
124
0
  }
125
0
126
0
  // Find the active field of the union.
127
0
  Record *R = U.getRecord();
128
0
  assert(R && R->isUnion() && "Not a union");
129
0
  const FieldDecl *ActiveField = nullptr;
130
0
  for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
131
0
    const Pointer &Field = U.atField(R->getField(I)->Offset);
132
0
    if (Field.isActive()) {
133
0
      ActiveField = Field.getField();
134
0
      break;
135
0
    }
136
0
  }
137
0
138
0
  const SourceInfo &Loc = S.Current->getSource(OpPC);
139
0
  S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
140
0
      << AK << InactiveField << !ActiveField << ActiveField;
141
0
  return false;
142
0
}
143
144
static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
145
0
                           AccessKinds AK) {
146
0
  if (auto ID = Ptr.getDeclID()) {
147
0
    if (!Ptr.isStaticTemporary())
148
0
      return true;
149
0
150
0
    if (Ptr.getDeclDesc()->getType().isConstQualified())
151
0
      return true;
152
0
153
0
    if (S.P.getCurrentDecl() == ID)
154
0
      return true;
155
0
156
0
    const SourceInfo &E = S.Current->getSource(OpPC);
157
0
    S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
158
0
    S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
159
0
    return false;
160
0
  }
161
0
  return true;
162
0
}
163
164
0
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
165
0
  if (auto ID = Ptr.getDeclID()) {
166
0
    if (!Ptr.isStatic())
167
0
      return true;
168
0
169
0
    if (S.P.getCurrentDecl() == ID)
170
0
      return true;
171
0
172
0
    S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
173
0
    return false;
174
0
  }
175
0
  return true;
176
0
}
177
178
namespace clang {
179
namespace interp {
180
181
0
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
182
0
  if (!Ptr.isExtern())
183
0
    return true;
184
0
185
0
  if (!S.checkingPotentialConstantExpression()) {
186
0
    auto *VD = Ptr.getDeclDesc()->asValueDecl();
187
0
    const SourceInfo &Loc = S.Current->getSource(OpPC);
188
0
    S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
189
0
    S.Note(VD->getLocation(), diag::note_declared_at);
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
  const auto &Src = S.Current->getSource(OpPC);
205
0
  if (Ptr.isZero()) {
206
0
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
0
212
0
    return false;
213
0
  }
214
0
215
0
  if (!Ptr.isLive()) {
216
0
    bool IsTemp = Ptr.isTemporary();
217
0
218
0
    S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
219
0
220
0
    if (IsTemp)
221
0
      S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
222
0
    else
223
0
      S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
224
0
225
0
    return false;
226
0
  }
227
0
228
0
  return true;
229
0
}
230
231
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
232
0
               CheckSubobjectKind CSK) {
233
0
  if (!Ptr.isZero())
234
0
    return true;
235
0
  const SourceInfo &Loc = S.Current->getSource(OpPC);
236
0
  S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
237
0
  return false;
238
0
}
239
240
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
241
0
                AccessKinds AK) {
242
0
  if (!Ptr.isOnePastEnd())
243
0
    return true;
244
0
  const SourceInfo &Loc = S.Current->getSource(OpPC);
245
0
  S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
246
0
  return false;
247
0
}
248
249
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
250
0
                CheckSubobjectKind CSK) {
251
0
  if (!Ptr.isElementPastEnd())
252
0
    return true;
253
0
  const SourceInfo &Loc = S.Current->getSource(OpPC);
254
0
  S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
255
0
  return false;
256
0
}
257
258
0
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
259
0
  assert(Ptr.isLive() && "Pointer is not live");
260
0
  if (!Ptr.isConst()) {
261
0
    return true;
262
0
  }
263
0
264
0
  const QualType Ty = Ptr.getType();
265
0
  const SourceInfo &Loc = S.Current->getSource(OpPC);
266
0
  S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
267
0
  return false;
268
0
}
269
270
0
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
271
0
  assert(Ptr.isLive() && "Pointer is not live");
272
0
  if (!Ptr.isMutable()) {
273
0
    return true;
274
0
  }
275
0
276
0
  const SourceInfo &Loc = S.Current->getSource(OpPC);
277
0
  const FieldDecl *Field = Ptr.getField();
278
0
  S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
279
0
  S.Note(Field->getLocation(), diag::note_declared_at);
280
0
  return false;
281
0
}
282
283
0
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
284
0
  if (!CheckLive(S, OpPC, Ptr, AK_Read))
285
0
    return false;
286
0
  if (!CheckExtern(S, OpPC, Ptr))
287
0
    return false;
288
0
  if (!CheckRange(S, OpPC, Ptr, AK_Read))
289
0
    return false;
290
0
  if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
291
0
    return false;
292
0
  if (!CheckActive(S, OpPC, Ptr, AK_Read))
293
0
    return false;
294
0
  if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
295
0
    return false;
296
0
  if (!CheckMutable(S, OpPC, Ptr))
297
0
    return false;
298
0
  return true;
299
0
}
300
301
0
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
302
0
  if (!CheckLive(S, OpPC, Ptr, AK_Assign))
303
0
    return false;
304
0
  if (!CheckExtern(S, OpPC, Ptr))
305
0
    return false;
306
0
  if (!CheckRange(S, OpPC, Ptr, AK_Assign))
307
0
    return false;
308
0
  if (!CheckGlobal(S, OpPC, Ptr))
309
0
    return false;
310
0
  if (!CheckConst(S, OpPC, Ptr))
311
0
    return false;
312
0
  return true;
313
0
}
314
315
0
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
316
0
  if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
317
0
    return false;
318
0
  if (!CheckExtern(S, OpPC, Ptr))
319
0
    return false;
320
0
  if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
321
0
    return false;
322
0
  return true;
323
0
}
324
325
0
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
326
0
  if (!CheckLive(S, OpPC, Ptr, AK_Assign))
327
0
    return false;
328
0
  if (!CheckRange(S, OpPC, Ptr, AK_Assign))
329
0
    return false;
330
0
  return true;
331
0
}
332
333
0
bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) {
334
0
  const SourceLocation &Loc = S.Current->getLocation(OpPC);
335
0
336
0
  if (F->isVirtual()) {
337
0
    if (!S.getLangOpts().CPlusPlus2a) {
338
0
      S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
339
0
      return false;
340
0
    }
341
0
  }
342
0
343
0
  if (!F->isConstexpr()) {
344
0
    if (S.getLangOpts().CPlusPlus11) {
345
0
      const FunctionDecl *DiagDecl = F->getDecl();
346
0
347
0
      // If this function is not constexpr because it is an inherited
348
0
      // non-constexpr constructor, diagnose that directly.
349
0
      auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
350
0
      if (CD && CD->isInheritingConstructor()) {
351
0
        auto *Inherited = CD->getInheritedConstructor().getConstructor();
352
0
        if (!Inherited->isConstexpr())
353
0
          DiagDecl = CD = Inherited;
354
0
      }
355
0
356
0
      // FIXME: If DiagDecl is an implicitly-declared special member function
357
0
      // or an inheriting constructor, we should be much more explicit about why
358
0
      // it's not constexpr.
359
0
      if (CD && CD->isInheritingConstructor())
360
0
        S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
361
0
          << CD->getInheritedConstructor().getConstructor()->getParent();
362
0
      else
363
0
        S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
364
0
          << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
365
0
      S.Note(DiagDecl->getLocation(), diag::note_declared_at);
366
0
    } else {
367
0
      S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
368
0
    }
369
0
    return false;
370
0
  }
371
0
372
0
  return true;
373
0
}
374
375
0
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
376
0
  if (!This.isZero())
377
0
    return true;
378
0
379
0
  const SourceInfo &Loc = S.Current->getSource(OpPC);
380
0
381
0
  bool IsImplicit = false;
382
0
  if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr()))
383
0
    IsImplicit = E->isImplicit();
384
0
385
0
  if (S.getLangOpts().CPlusPlus11)
386
0
    S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
387
0
  else
388
0
    S.FFDiag(Loc);
389
0
390
0
  return false;
391
0
}
392
393
0
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
394
0
  if (!MD->isPure())
395
0
    return true;
396
0
  const SourceInfo &E = S.Current->getSource(OpPC);
397
0
  S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
398
0
  S.Note(MD->getLocation(), diag::note_declared_at);
399
0
  return false;
400
0
}
401
1
bool Interpret(InterpState &S, APValue &Result) {
402
1
  CodePtr PC = S.Current->getPC();
403
1
404
1
  for (;;) {
405
1
    auto Op = PC.read<Opcode>();
406
1
    CodePtr OpPC = PC;
407
1
408
1
    switch (Op) {
409
0
#define GET_INTERP
410
0
#include "Opcodes.inc"
411
1
#undef GET_INTERP
412
1
    }
413
1
  }
414
1
}
415
416
} // namespace interp
417
} // namespace clang