Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- 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 "ByteCodeStmtGen.h"
10
#include "ByteCodeEmitter.h"
11
#include "ByteCodeGenError.h"
12
#include "Context.h"
13
#include "Function.h"
14
#include "PrimType.h"
15
#include "Program.h"
16
#include "State.h"
17
#include "clang/Basic/LLVM.h"
18
19
using namespace clang;
20
using namespace clang::interp;
21
22
namespace clang {
23
namespace interp {
24
25
/// Scope managing label targets.
26
template <class Emitter> class LabelScope {
27
public:
28
  virtual ~LabelScope() {  }
29
30
protected:
31
  LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
32
  /// ByteCodeStmtGen instance.
33
  ByteCodeStmtGen<Emitter> *Ctx;
34
};
35
36
/// Sets the context for break/continue statements.
37
template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
38
public:
39
  using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
40
  using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
41
42
  LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
43
            LabelTy ContinueLabel)
44
      : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
45
        OldContinueLabel(Ctx->ContinueLabel) {
46
    this->Ctx->BreakLabel = BreakLabel;
47
    this->Ctx->ContinueLabel = ContinueLabel;
48
  }
49
50
  ~LoopScope() {
51
    this->Ctx->BreakLabel = OldBreakLabel;
52
    this->Ctx->ContinueLabel = OldContinueLabel;
53
  }
54
55
private:
56
  OptLabelTy OldBreakLabel;
57
  OptLabelTy OldContinueLabel;
58
};
59
60
// Sets the context for a switch scope, mapping labels.
61
template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
62
public:
63
  using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
64
  using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
65
  using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
66
67
  SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
68
              LabelTy BreakLabel, OptLabelTy DefaultLabel)
69
      : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
70
        OldDefaultLabel(this->Ctx->DefaultLabel),
71
        OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
72
    this->Ctx->BreakLabel = BreakLabel;
73
    this->Ctx->DefaultLabel = DefaultLabel;
74
    this->Ctx->CaseLabels = std::move(CaseLabels);
75
  }
76
77
  ~SwitchScope() {
78
    this->Ctx->BreakLabel = OldBreakLabel;
79
    this->Ctx->DefaultLabel = OldDefaultLabel;
80
    this->Ctx->CaseLabels = std::move(OldCaseLabels);
81
  }
82
83
private:
84
  OptLabelTy OldBreakLabel;
85
  OptLabelTy OldDefaultLabel;
86
  CaseMap OldCaseLabels;
87
};
88
89
} // namespace interp
90
} // namespace clang
91
92
template <class Emitter>
93
2
bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
94
  // Classify the return type.
95
2
  ReturnType = this->classify(F->getReturnType());
96
97
  // Set up fields and context if a constructor.
98
2
  if (auto *MD = dyn_cast<CXXMethodDecl>(F))
99
0
    return this->bail(MD);
100
101
2
  if (auto *Body = F->getBody())
102
2
    if (!visitStmt(Body))
103
1
      return false;
104
105
  // Emit a guard return to protect against a code path missing one.
106
1
  if (F->getReturnType()->isVoidType())
107
0
    return this->emitRetVoid(SourceInfo{});
108
1
  else
109
1
    return this->emitNoRet(SourceInfo{});
110
1
}
111
112
template <class Emitter>
113
11
bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
114
11
  switch (S->getStmtClass()) {
115
5
  case Stmt::CompoundStmtClass:
116
5
    return visitCompoundStmt(cast<CompoundStmt>(S));
117
1
  case Stmt::DeclStmtClass:
118
1
    return visitDeclStmt(cast<DeclStmt>(S));
119
2
  case Stmt::ReturnStmtClass:
120
2
    return visitReturnStmt(cast<ReturnStmt>(S));
121
2
  case Stmt::IfStmtClass:
122
2
    return visitIfStmt(cast<IfStmt>(S));
123
0
  case Stmt::NullStmtClass:
124
0
    return true;
125
1
  default: {
126
1
    if (auto *Exp = dyn_cast<Expr>(S))
127
1
      return this->discard(Exp);
128
0
    return this->bail(S);
129
1
  }
130
11
  }
131
11
}
132
133
template <class Emitter>
134
bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
135
5
    const CompoundStmt *CompoundStmt) {
136
5
  BlockScope<Emitter> Scope(this);
137
5
  for (auto *InnerStmt : CompoundStmt->body())
138
6
    if (!visitStmt(InnerStmt))
139
2
      return false;
140
3
  return true;
141
5
}
142
143
template <class Emitter>
144
1
bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
145
1
  for (auto *D : DS->decls()) {
146
    // Variable declarator.
147
1
    if (auto *VD = dyn_cast<VarDecl>(D)) {
148
1
      if (!visitVarDecl(VD))
149
0
        return false;
150
1
      continue;
151
1
    }
152
153
    // Decomposition declarator.
154
0
    if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
155
0
      return this->bail(DD);
156
0
    }
157
0
  }
158
159
1
  return true;
160
1
}
161
162
template <class Emitter>
163
2
bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
164
2
  if (const Expr *RE = RS->getRetValue()) {
165
2
    ExprScope<Emitter> RetScope(this);
166
2
    if (ReturnType) {
167
      // Primitive types are simply returned.
168
2
      if (!this->visit(RE))
169
0
        return false;
170
2
      this->emitCleanup();
171
2
      return this->emitRet(*ReturnType, RS);
172
2
    } else {
173
      // RVO - construct the value in the return location.
174
0
      auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); };
175
0
      if (!this->visitInitializer(RE, ReturnLocation))
176
0
        return false;
177
0
      this->emitCleanup();
178
0
      return this->emitRetVoid(RS);
179
0
    }
180
2
  } else {
181
0
    this->emitCleanup();
182
0
    if (!this->emitRetVoid(RS))
183
0
      return false;
184
0
    return true;
185
0
  }
186
2
}
187
188
template <class Emitter>
189
2
bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
190
2
  BlockScope<Emitter> IfScope(this);
191
192
2
  if (IS->isNonNegatedConsteval())
193
1
    return visitStmt(IS->getThen());
194
1
  if (IS->isNegatedConsteval())
195
0
    return IS->getElse() ? visitStmt(IS->getElse()) : true;
196
197
1
  if (auto *CondInit = IS->getInit())
198
0
    if (!visitStmt(IS->getInit()))
199
0
      return false;
200
201
1
  if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
202
0
    if (!visitDeclStmt(CondDecl))
203
0
      return false;
204
205
1
  if (!this->visitBool(IS->getCond()))
206
0
    return false;
207
208
1
  if (const Stmt *Else = IS->getElse()) {
209
1
    LabelTy LabelElse = this->getLabel();
210
1
    LabelTy LabelEnd = this->getLabel();
211
1
    if (!this->jumpFalse(LabelElse))
212
0
      return false;
213
1
    if (!visitStmt(IS->getThen()))
214
0
      return false;
215
1
    if (!this->jump(LabelEnd))
216
0
      return false;
217
1
    this->emitLabel(LabelElse);
218
1
    if (!visitStmt(Else))
219
0
      return false;
220
1
    this->emitLabel(LabelEnd);
221
1
  } else {
222
0
    LabelTy LabelEnd = this->getLabel();
223
0
    if (!this->jumpFalse(LabelEnd))
224
0
      return false;
225
0
    if (!visitStmt(IS->getThen()))
226
0
      return false;
227
0
    this->emitLabel(LabelEnd);
228
0
  }
229
230
1
  return true;
231
1
}
232
233
template <class Emitter>
234
1
bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
235
1
  auto DT = VD->getType();
236
237
1
  if (!VD->hasLocalStorage()) {
238
    // No code generation required.
239
0
    return true;
240
0
  }
241
242
  // Integers, pointers, primitives.
243
1
  if (Optional<PrimType> T = this->classify(DT)) {
244
1
    auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
245
    // Compile the initialiser in its own scope.
246
1
    {
247
1
      ExprScope<Emitter> Scope(this);
248
1
      if (!this->visit(VD->getInit()))
249
0
        return false;
250
1
    }
251
    // Set the value.
252
1
    return this->emitSetLocal(*T, Off, VD);
253
1
  } else {
254
    // Composite types - allocate storage and initialize it.
255
0
    if (auto Off = this->allocateLocal(VD)) {
256
0
      return this->visitLocalInitializer(VD->getInit(), *Off);
257
0
    } else {
258
0
      return this->bail(VD);
259
0
    }
260
0
  }
261
1
}
262
263
namespace clang {
264
namespace interp {
265
266
template class ByteCodeStmtGen<ByteCodeEmitter>;
267
268
} // namespace interp
269
} // namespace clang