clang  10.0.0svn
Interp.cpp
Go to the documentation of this file.
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"
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 static bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
35  S.CallStackDepth--;
36  const T &Ret = S.Stk.pop<T>();
37 
38  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
40  S.Current->popArgs();
41 
42  if (InterpFrame *Caller = S.Current->Caller) {
43  PC = S.Current->getRetPC();
44  delete S.Current;
45  S.Current = Caller;
46  S.Stk.push<T>(Ret);
47  } else {
48  delete S.Current;
49  S.Current = nullptr;
50  if (!ReturnValue<T>(Ret, Result))
51  return false;
52  }
53  return true;
54 }
55 
56 static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
57  S.CallStackDepth--;
58 
59  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
61  S.Current->popArgs();
62 
63  if (InterpFrame *Caller = S.Current->Caller) {
64  PC = S.Current->getRetPC();
65  delete S.Current;
66  S.Current = Caller;
67  } else {
68  delete S.Current;
69  S.Current = nullptr;
70  }
71  return true;
72 }
73 
74 static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
75  llvm::report_fatal_error("Interpreter cannot return values");
76 }
77 
78 //===----------------------------------------------------------------------===//
79 // Jmp, Jt, Jf
80 //===----------------------------------------------------------------------===//
81 
82 static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
83  PC += Offset;
84  return true;
85 }
86 
87 static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
88  if (S.Stk.pop<bool>()) {
89  PC += Offset;
90  }
91  return true;
92 }
93 
94 static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
95  if (!S.Stk.pop<bool>()) {
96  PC += Offset;
97  }
98  return true;
99 }
100 
101 static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
102  AccessKinds AK) {
103  if (Ptr.isInitialized())
104  return true;
106  const SourceInfo &Loc = S.Current->getSource(OpPC);
107  S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
108  }
109  return false;
110 }
111 
112 static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
113  AccessKinds AK) {
114  if (Ptr.isActive())
115  return true;
116 
117  // Get the inactive field descriptor.
118  const FieldDecl *InactiveField = Ptr.getField();
119 
120  // Walk up the pointer chain to find the union which is not active.
121  Pointer U = Ptr.getBase();
122  while (!U.isActive()) {
123  U = U.getBase();
124  }
125 
126  // Find the active field of the union.
127  Record *R = U.getRecord();
128  assert(R && R->isUnion() && "Not a union");
129  const FieldDecl *ActiveField = nullptr;
130  for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
131  const Pointer &Field = U.atField(R->getField(I)->Offset);
132  if (Field.isActive()) {
133  ActiveField = Field.getField();
134  break;
135  }
136  }
137 
138  const SourceInfo &Loc = S.Current->getSource(OpPC);
139  S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
140  << AK << InactiveField << !ActiveField << ActiveField;
141  return false;
142 }
143 
144 static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
145  AccessKinds AK) {
146  if (auto ID = Ptr.getDeclID()) {
147  if (!Ptr.isStaticTemporary())
148  return true;
149 
150  if (Ptr.getDeclDesc()->getType().isConstQualified())
151  return true;
152 
153  if (S.P.getCurrentDecl() == ID)
154  return true;
155 
156  const SourceInfo &E = S.Current->getSource(OpPC);
157  S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
158  S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
159  return false;
160  }
161  return true;
162 }
163 
164 static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
165  if (auto ID = Ptr.getDeclID()) {
166  if (!Ptr.isStatic())
167  return true;
168 
169  if (S.P.getCurrentDecl() == ID)
170  return true;
171 
172  S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
173  return false;
174  }
175  return true;
176 }
177 
178 namespace clang {
179 namespace interp {
180 
181 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
182  if (!Ptr.isExtern())
183  return true;
184 
186  auto *VD = Ptr.getDeclDesc()->asValueDecl();
187  const SourceInfo &Loc = S.Current->getSource(OpPC);
188  S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
189  S.Note(VD->getLocation(), diag::note_declared_at);
190  }
191  return false;
192 }
193 
194 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
195  if (!Ptr.isUnknownSizeArray())
196  return true;
197  const SourceInfo &E = S.Current->getSource(OpPC);
198  S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
199  return false;
200 }
201 
202 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
203  AccessKinds AK) {
204  const auto &Src = S.Current->getSource(OpPC);
205  if (Ptr.isZero()) {
206 
207  if (Ptr.isField())
208  S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
209  else
210  S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
211 
212  return false;
213  }
214 
215  if (!Ptr.isLive()) {
216  bool IsTemp = Ptr.isTemporary();
217 
218  S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
219 
220  if (IsTemp)
221  S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
222  else
223  S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
224 
225  return false;
226  }
227 
228  return true;
229 }
230 
231 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
232  CheckSubobjectKind CSK) {
233  if (!Ptr.isZero())
234  return true;
235  const SourceInfo &Loc = S.Current->getSource(OpPC);
236  S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
237  return false;
238 }
239 
240 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
241  AccessKinds AK) {
242  if (!Ptr.isOnePastEnd())
243  return true;
244  const SourceInfo &Loc = S.Current->getSource(OpPC);
245  S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
246  return false;
247 }
248 
249 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
250  CheckSubobjectKind CSK) {
251  if (!Ptr.isElementPastEnd())
252  return true;
253  const SourceInfo &Loc = S.Current->getSource(OpPC);
254  S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
255  return false;
256 }
257 
258 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
259  assert(Ptr.isLive() && "Pointer is not live");
260  if (!Ptr.isConst()) {
261  return true;
262  }
263 
264  const QualType Ty = Ptr.getType();
265  const SourceInfo &Loc = S.Current->getSource(OpPC);
266  S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
267  return false;
268 }
269 
270 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
271  assert(Ptr.isLive() && "Pointer is not live");
272  if (!Ptr.isMutable()) {
273  return true;
274  }
275 
276  const SourceInfo &Loc = S.Current->getSource(OpPC);
277  const FieldDecl *Field = Ptr.getField();
278  S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
279  S.Note(Field->getLocation(), diag::note_declared_at);
280  return false;
281 }
282 
283 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
284  if (!CheckLive(S, OpPC, Ptr, AK_Read))
285  return false;
286  if (!CheckExtern(S, OpPC, Ptr))
287  return false;
288  if (!CheckRange(S, OpPC, Ptr, AK_Read))
289  return false;
290  if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
291  return false;
292  if (!CheckActive(S, OpPC, Ptr, AK_Read))
293  return false;
294  if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
295  return false;
296  if (!CheckMutable(S, OpPC, Ptr))
297  return false;
298  return true;
299 }
300 
301 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
302  if (!CheckLive(S, OpPC, Ptr, AK_Assign))
303  return false;
304  if (!CheckExtern(S, OpPC, Ptr))
305  return false;
306  if (!CheckRange(S, OpPC, Ptr, AK_Assign))
307  return false;
308  if (!CheckGlobal(S, OpPC, Ptr))
309  return false;
310  if (!CheckConst(S, OpPC, Ptr))
311  return false;
312  return true;
313 }
314 
315 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
316  if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
317  return false;
318  if (!CheckExtern(S, OpPC, Ptr))
319  return false;
320  if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
321  return false;
322  return true;
323 }
324 
325 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
326  if (!CheckLive(S, OpPC, Ptr, AK_Assign))
327  return false;
328  if (!CheckRange(S, OpPC, Ptr, AK_Assign))
329  return false;
330  return true;
331 }
332 
334  const SourceLocation &Loc = S.Current->getLocation(OpPC);
335 
336  if (F->isVirtual()) {
337  if (!S.getLangOpts().CPlusPlus2a) {
338  S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
339  return false;
340  }
341  }
342 
343  if (!F->isConstexpr()) {
344  if (S.getLangOpts().CPlusPlus11) {
345  const FunctionDecl *DiagDecl = F->getDecl();
346 
347  // If this function is not constexpr because it is an inherited
348  // non-constexpr constructor, diagnose that directly.
349  auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
350  if (CD && CD->isInheritingConstructor()) {
351  auto *Inherited = CD->getInheritedConstructor().getConstructor();
352  if (!Inherited->isConstexpr())
353  DiagDecl = CD = Inherited;
354  }
355 
356  // FIXME: If DiagDecl is an implicitly-declared special member function
357  // or an inheriting constructor, we should be much more explicit about why
358  // it's not constexpr.
359  if (CD && CD->isInheritingConstructor())
360  S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
361  << CD->getInheritedConstructor().getConstructor()->getParent();
362  else
363  S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
364  << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
365  S.Note(DiagDecl->getLocation(), diag::note_declared_at);
366  } else {
367  S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
368  }
369  return false;
370  }
371 
372  return true;
373 }
374 
375 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
376  if (!This.isZero())
377  return true;
378 
379  const SourceInfo &Loc = S.Current->getSource(OpPC);
380 
381  bool IsImplicit = false;
382  if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr()))
383  IsImplicit = E->isImplicit();
384 
385  if (S.getLangOpts().CPlusPlus11)
386  S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
387  else
388  S.FFDiag(Loc);
389 
390  return false;
391 }
392 
393 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
394  if (!MD->isPure())
395  return true;
396  const SourceInfo &E = S.Current->getSource(OpPC);
397  S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
398  S.Note(MD->getLocation(), diag::note_declared_at);
399  return false;
400 }
401 bool Interpret(InterpState &S, APValue &Result) {
402  CodePtr PC = S.Current->getPC();
403 
404  for (;;) {
405  auto Op = PC.read<Opcode>();
406  CodePtr OpPC = PC;
407 
408  switch (Op) {
409 #define GET_INTERP
410 #include "Opcodes.inc"
411 #undef GET_INTERP
412  }
413  }
414 }
415 
416 } // namespace interp
417 } // namespace clang
Defines the clang::ASTContext interface.
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:315
Represents a function declaration or definition.
Definition: Decl.h:1784
A (possibly-)qualified type.
Definition: Type.h:643
bool isMutable() const
Checks if the field is mutable.
Definition: Pointer.h:238
InterpFrame * Current
The current frame.
Definition: InterpState.h:104
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:231
Pointer into the code segment.
Definition: Source.h:25
SourceLocation getLocation(CodePtr PC) const
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
Definition: Decl.h:2144
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:393
void push(Tys &&... Args)
Constructs a value in place on the top of the stack.
Definition: InterpStack.h:30
Frame storing local variables.
Definition: InterpFrame.h:29
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:277
llvm::Optional< unsigned > getCurrentDecl() const
Returns the current declaration ID.
Definition: Program.h:124
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition: Function.h:74
Represents a C++ constructor within a class.
Definition: DeclCXX.h:2365
QualType getType() const
Definition: Descriptor.cpp:245
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:830
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:81
Defines the clang::Expr interface and subclasses for C++ expressions.
A pointer to a memory block, live or dead.
Definition: Pointer.h:39
InterpFrame * Caller
The frame of the previous function.
Definition: InterpFrame.h:32
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:401
Represents a member of a struct/union/class.
Definition: Decl.h:2643
T pop()
Returns the value from the top of the stack and removes it.
Definition: InterpStack.h:35
InterpStack & Stk
Temporary stack.
Definition: InterpState.h:100
InheritedConstructor getInheritedConstructor() const
Get the constructor that this inheriting constructor is based on.
Definition: DeclCXX.h:2602
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
Definition: State.h:26
static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:87
Structure/Class descriptor.
Definition: Record.h:23
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:231
static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:101
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:115
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:242
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:178
T read()
Reads data and advances the pointer.
Definition: Source.h:47
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
Definition: Interp.cpp:181
void popArgs()
Pops the arguments off the stack.
Definition: InterpFrame.cpp:51
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accesible.
Definition: Interp.cpp:202
llvm::Optional< unsigned > getDeclID() const
Returns the declaration ID.
Definition: Pointer.h:252
bool isUnion() const
Checks if the record is a union.
Definition: Record.h:51
unsigned Offset
Definition: Format.cpp:1809
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:144
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:194
static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:82
#define bool
Definition: stdbool.h:15
virtual SourceInfo getSource(CodePtr PC) const
Map a location to a source.
unsigned getNumFields()
Definition: Record.h:68
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Definition: State.cpp:20
static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.cpp:56
size_t getFrameOffset() const
Returns the offset on the stack at which the frame starts.
Definition: InterpFrame.h:63
bool isStaticTemporary() const
Checks if the storage is a static temporary.
Definition: Pointer.h:235
static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:144
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition: Type.h:6207
Encodes a location in the source.
bool isPure() const
Whether this virtual function is pure, i.e.
Definition: Decl.h:2059
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:229
static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset)
Definition: Interp.cpp:94
static bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.cpp:34
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:1905
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.cpp:164
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:301
Bytecode function.
Definition: Function.h:59
bool isVirtual() const
Checks if the function is virtual.
Definition: Function.cpp:44
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition: State.cpp:62
bool isTemporary() const
Checks if the storage is temporary.
Definition: Pointer.h:233
static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result)
Definition: Interp.cpp:74
unsigned CallStackDepth
Call stack depth.
Definition: InterpState.h:106
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:258
CXXConstructorDecl * getConstructor() const
Definition: DeclCXX.h:2352
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:270
SourceLocation getDeclLoc() const
Definition: Pointer.h:148
Dataflow Directional Tag Classes.
CodePtr getPC() const
Returns the PC of the frame&#39;s code start.
Definition: InterpFrame.h:103
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:240
bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F)
Checks if a method can be called.
Definition: Interp.cpp:333
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:142
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:135
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:210
Interpreter context.
Definition: InterpState.h:34
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:272
Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:221
size_t size() const
Returns the size of the stack in bytes.
Definition: InterpStack.h:59
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:70
Program & P
Reference to the module containing all bytecode.
Definition: InterpState.h:98
const FieldDecl * getField() const
Returns the field information.
Definition: Pointer.h:223
const LangOptions & getLangOpts() const
Definition: State.cpp:115
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:140
Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:147
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat]...
Definition: APValue.h:115
OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation does not produce a C++11 core constant expression.
Definition: State.cpp:41
bool isConstexpr() const
Checks if the function is valid to call in constexpr.
Definition: Function.h:103
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the &#39;this&#39; pointer.
Definition: Interp.cpp:375
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:283
bool isConst() const
Checks if an object or a subfield is mutable.
Definition: Pointer.h:247
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:325
static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:112
bool checkingPotentialConstantExpression() const override
Definition: InterpState.h:62
CheckSubobjectKind
Definition: State.h:40
const Expr * asExpr() const
Definition: Source.cpp:25
const Field * getField(const FieldDecl *FD) const
Returns a field.
Definition: Record.cpp:30
CodePtr getRetPC() const
Returns the return address of the frame.
Definition: InterpFrame.h:106
SourceLocation getLocation() const
Definition: DeclBase.h:429
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:151