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