1//===--- State.h - State chain for the VM and AST Walker --------*- 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// Defines the base class of the interpreter and evaluator state.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_STATE_H
14#define LLVM_CLANG_AST_INTERP_STATE_H
15
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/ASTDiagnostic.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/OptionalDiagnostic.h"
20
21namespace clang {
22class OptionalDiagnostic;
23
24/// Kinds of access we can perform on an object, for diagnostics. Note that
25/// we consider a member function call to be a kind of access, even though
26/// it is not formally an access of the object, because it has (largely) the
27/// same set of semantic restrictions.
28enum AccessKinds {
29 AK_Read,
30 AK_ReadObjectRepresentation,
31 AK_Assign,
32 AK_Increment,
33 AK_Decrement,
34 AK_MemberCall,
35 AK_DynamicCast,
36 AK_TypeId,
37 AK_Construct,
38 AK_Destroy,
39 AK_IsWithinLifetime,
40 AK_Dereference
41};
42
43/// The order of this enum is important for diagnostics.
44enum CheckSubobjectKind {
45 CSK_Base,
46 CSK_Derived,
47 CSK_Field,
48 CSK_ArrayToPointer,
49 CSK_ArrayIndex,
50 CSK_Real,
51 CSK_Imag,
52 CSK_VectorElement
53};
54
55enum class EvaluationMode {
56 /// Evaluate as a constant expression. Stop if we find that the expression
57 /// is not a constant expression.
58 ConstantExpression,
59
60 /// Evaluate as a constant expression. Stop if we find that the expression
61 /// is not a constant expression. Some expressions can be retried in the
62 /// optimizer if we don't constant fold them here, but in an unevaluated
63 /// context we try to fold them immediately since the optimizer never
64 /// gets a chance to look at it.
65 ConstantExpressionUnevaluated,
66
67 /// Fold the expression to a constant. Stop if we hit a side-effect that
68 /// we can't model.
69 ConstantFold,
70
71 /// Evaluate in any way we know how. Don't worry about side-effects that
72 /// can't be modeled.
73 IgnoreSideEffects,
74};
75
76namespace interp {
77class Frame;
78class SourceInfo;
79
80/// Interface for the VM to interact with the AST walker's context.
81class State {
82public:
83 State(ASTContext &ASTCtx, Expr::EvalStatus &EvalStatus)
84 : Ctx(ASTCtx), EvalStatus(EvalStatus) {}
85 virtual ~State();
86
87 virtual const Frame *getCurrentFrame() = 0;
88 virtual unsigned getCallStackDepth() = 0;
89 virtual bool stepsLeft() const = 0;
90
91 Expr::EvalStatus &getEvalStatus() const { return EvalStatus; }
92 ASTContext &getASTContext() const { return Ctx; }
93 const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
94
95 /// If \c DiagId should be relaxed as per the current evaluation settings,
96 /// emit it as a warning instead of an error. Returns \c true if a relaxed
97 /// diagnostic was emitted, \c false otherwise.
98 bool emitRelaxedDiag(SourceLocation Loc, diag::kind DiagId);
99
100 /// Note that we have had a side-effect, and determine whether we should
101 /// keep evaluating.
102 bool noteSideEffect() const {
103 EvalStatus.HasSideEffects = true;
104 return keepEvaluatingAfterSideEffect();
105 }
106
107 /// Should we continue evaluation as much as possible after encountering a
108 /// construct which can't be reduced to a value?
109 bool keepEvaluatingAfterFailure() const;
110 /// Should we continue evaluation after encountering a side-effect that we
111 /// couldn't model?
112 bool keepEvaluatingAfterSideEffect() const;
113
114 /// Note that we hit something that was technically undefined behavior, but
115 /// that we can evaluate past it (such as signed overflow or floating-point
116 /// division by zero.)
117 bool noteUndefinedBehavior() const {
118 EvalStatus.HasUndefinedBehavior = true;
119 return keepEvaluatingAfterUndefinedBehavior();
120 }
121
122 /// Are we checking whether the expression is a potential constant
123 /// expression?
124 bool checkingPotentialConstantExpression() const {
125 return CheckingPotentialConstantExpression;
126 }
127 /// Are we checking an expression for overflow?
128 bool checkingForUndefinedBehavior() const {
129 return CheckingForUndefinedBehavior;
130 }
131
132 /// Diagnose that the evaluation could not be folded (FF => FoldFailure)
133 OptionalDiagnostic
134 FFDiag(SourceLocation Loc,
135 diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
136 unsigned ExtraNotes = 0);
137
138 OptionalDiagnostic
139 FFDiag(const Expr *E,
140 diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
141 unsigned ExtraNotes = 0);
142
143 OptionalDiagnostic
144 FFDiag(SourceInfo SI,
145 diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
146 unsigned ExtraNotes = 0);
147
148 /// Diagnose that the evaluation does not produce a C++11 core constant
149 /// expression.
150 ///
151 /// FIXME: Stop evaluating if we're in EM_ConstantExpression or
152 /// EM_PotentialConstantExpression mode and we produce one of these.
153 OptionalDiagnostic
154 CCEDiag(SourceLocation Loc,
155 diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
156 unsigned ExtraNotes = 0);
157
158 OptionalDiagnostic
159 CCEDiag(const Expr *E,
160 diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
161 unsigned ExtraNotes = 0);
162
163 OptionalDiagnostic
164 CCEDiag(SourceInfo SI,
165 diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
166 unsigned ExtraNotes = 0);
167
168 /// Add a note to a prior diagnostic.
169 OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId);
170 OptionalDiagnostic Note(SourceInfo Loc, diag::kind DiagId);
171
172 /// Add a stack of notes to a prior diagnostic.
173 void addNotes(ArrayRef<PartialDiagnosticAt> Diags);
174
175 /// Directly reports a diagnostic message.
176 DiagnosticBuilder report(SourceLocation Loc, diag::kind DiagId);
177
178 /// Whether or not we're in a context where the front end requires a
179 /// constant value.
180 bool InConstantContext = false;
181
182 /// Whether we're checking that an expression is a potential constant
183 /// expression. If so, do not fail on constructs that could become constant
184 /// later on (such as a use of an undefined global).
185 bool CheckingPotentialConstantExpression = false;
186
187 /// Whether we're checking for an expression that has undefined behavior.
188 /// If so, we will produce warnings if we encounter an operation that is
189 /// always undefined.
190 ///
191 /// Note that we still need to evaluate the expression normally when this
192 /// is set; this is used when evaluating ICEs in C.
193 bool CheckingForUndefinedBehavior = false;
194
195 EvaluationMode EvalMode;
196 ASTContext &Ctx;
197 Expr::EvalStatus &EvalStatus;
198
199private:
200 /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
201 /// notes attached to it will also be stored, otherwise they will not be.
202 bool HasActiveDiagnostic = false;
203
204 /// Have we emitted a diagnostic explaining why we couldn't constant
205 /// fold (not just why it's not strictly a constant expression)?
206 bool HasFoldFailureDiagnostic = false;
207
208 void addCallStack(unsigned Limit);
209
210 PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId);
211
212 void addExtendedDiag(SourceLocation Loc, diag::kind DiagId);
213
214 OptionalDiagnostic diag(SourceLocation Loc, diag::kind DiagId,
215 unsigned ExtraNotes, bool IsCCEDiag);
216
217 /// Should we continue evaluation after encountering undefined behavior?
218 bool keepEvaluatingAfterUndefinedBehavior() const;
219
220 // If we have a prior diagnostic, it will be noting that the expression
221 // isn't a constant expression. This diagnostic is more important,
222 // unless we require this evaluation to produce a constant expression.
223 //
224 // FIXME: We might want to show both diagnostics to the user in
225 // EvaluationMode::ConstantFold mode.
226 bool hasPriorDiagnostic();
227
228 void setFoldFailureDiagnostic(bool Flag) { HasFoldFailureDiagnostic = Flag; };
229 void setActiveDiagnostic(bool Flag) { HasActiveDiagnostic = Flag; };
230 bool hasActiveDiagnostic() const { return HasActiveDiagnostic; }
231};
232
233} // namespace interp
234} // namespace clang
235
236#endif
237