clang 24.0.0git
State.cpp
Go to the documentation of this file.
1//===--- State.cpp - 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#include "State.h"
10#include "Frame.h"
11#include "Source.h"
14
15using namespace clang;
16using namespace clang::interp;
17
19
21 if (!Ctx.getLangOpts().MSVCCompat ||
22 (!EvalStatus.ExtendedDiag && !InConstantContext))
23 return false;
24
25 switch (DiagId) {
26 case diag::note_constexpr_invalid_cast_ptrtoint:
27 addExtendedDiag(Loc, diag::warn_relaxed_constant_fold_cast);
28 return true;
29 case diag::note_constexpr_null_subobject:
30 addExtendedDiag(Loc, diag::warn_relaxed_constant_fold_null);
31 return true;
32 default:
33 return false;
34 }
35}
36
38 unsigned ExtraNotes) {
39 return diag(Loc, DiagId, ExtraNotes, false);
40}
41
43 unsigned ExtraNotes) {
44 EvalStatus.DiagEmitted = true;
45 if (EvalStatus.Diag)
46 return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
47 setActiveDiagnostic(false);
48 return OptionalDiagnostic();
49}
50
52 unsigned ExtraNotes) {
53 EvalStatus.DiagEmitted = true;
54 if (EvalStatus.Diag)
55 return diag(SI.getLoc(), DiagId, ExtraNotes, false);
56 setActiveDiagnostic(false);
57 return OptionalDiagnostic();
58}
59
61 unsigned ExtraNotes) {
62 if (emitRelaxedDiag(Loc, DiagId)) {
63 setActiveDiagnostic(false);
64 return OptionalDiagnostic();
65 }
66 EvalStatus.DiagEmitted = true;
67 // Don't override a previous diagnostic. Don't bother collecting
68 // diagnostics if we're evaluating for overflow.
69 if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
70 setActiveDiagnostic(false);
71 return OptionalDiagnostic();
72 }
73 return diag(Loc, DiagId, ExtraNotes, true);
74}
75
77 unsigned ExtraNotes) {
78 return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
79}
80
82 unsigned ExtraNotes) {
83 return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
84}
85
87 if (!hasActiveDiagnostic())
88 return OptionalDiagnostic();
89 return OptionalDiagnostic(&addDiag(Loc, DiagId));
90}
91
93 if (!hasActiveDiagnostic())
94 return OptionalDiagnostic();
95 return OptionalDiagnostic(&addDiag(SI.getLoc(), DiagId));
96}
97
99 if (hasActiveDiagnostic())
100 llvm::append_range(*EvalStatus.Diag, Diags);
101}
102
104 return Ctx.getDiagnostics().Report(Loc, DiagId);
105}
106
107/// Add a diagnostic to the diagnostics list.
108PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
109 PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
110 EvalStatus.Diag->push_back(std::make_pair(Loc, PD));
111 return EvalStatus.Diag->back().second;
112}
113
114void State::addExtendedDiag(SourceLocation Loc, diag::kind DiagId) {
115 if (!EvalStatus.ExtendedDiag)
116 return;
117 PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
118 EvalStatus.ExtendedDiag->push_back(std::make_pair(Loc, PD));
119}
120
121OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
122 unsigned ExtraNotes, bool IsCCEDiag) {
123 if (EvalStatus.Diag) {
124 if (hasPriorDiagnostic()) {
125 return OptionalDiagnostic();
126 }
127
128 unsigned CallStackNotes = getCallStackDepth() - 1;
129 unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
130 if (Limit)
131 CallStackNotes = std::min(CallStackNotes, Limit + 1);
132 if (checkingPotentialConstantExpression())
133 CallStackNotes = 0;
134
135 setActiveDiagnostic(true);
136 setFoldFailureDiagnostic(!IsCCEDiag);
137 EvalStatus.Diag->clear();
138 EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
139 addDiag(Loc, DiagId);
140 if (!checkingPotentialConstantExpression()) {
141 addCallStack(Limit);
142 }
143 return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
144 }
145 setActiveDiagnostic(false);
146 return OptionalDiagnostic();
147}
148
149void State::addCallStack(unsigned Limit) {
150 // Determine which calls to skip, if any.
151 unsigned ActiveCalls = getCallStackDepth() - 1;
152 unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart;
153 if (Limit && Limit < ActiveCalls) {
154 SkipStart = Limit / 2 + Limit % 2;
155 SkipEnd = ActiveCalls - Limit / 2;
156 }
157
158 // Walk the call stack and add the diagnostics.
159 unsigned CallIdx = 0;
160 const Frame *Top = getCurrentFrame();
161 for (const Frame *F = Top; F->getCaller() != nullptr;
162 F = F->getCaller(), ++CallIdx) {
163 SourceRange CallRange = F->getCallRange();
164 assert(CallRange.isValid());
165
166 // Skip this call?
167 if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
168 if (CallIdx == SkipStart) {
169 // Note that we're skipping calls.
170 addDiag(CallRange.getBegin(), diag::note_constexpr_calls_suppressed)
171 << unsigned(ActiveCalls - Limit);
172 }
173 continue;
174 }
175
176 // Use a different note for an inheriting constructor, because from the
177 // user's perspective it's not really a function at all.
178 if (const auto *CD =
179 dyn_cast_if_present<CXXConstructorDecl>(F->getCallee());
180 CD && CD->isInheritingConstructor()) {
181 addDiag(CallRange.getBegin(),
182 diag::note_constexpr_inherited_ctor_call_here)
183 << CD->getParent();
184 continue;
185 }
186
187 SmallString<128> Buffer;
188 llvm::raw_svector_ostream Out(Buffer);
189 F->describe(Out);
190 if (!Buffer.empty())
191 addDiag(CallRange.getBegin(), diag::note_constexpr_call_here)
192 << Out.str() << CallRange;
193 }
194}
195
196bool State::hasPriorDiagnostic() {
197 if (!EvalStatus.Diag->empty()) {
198 switch (EvalMode) {
199 case EvaluationMode::ConstantFold:
200 case EvaluationMode::IgnoreSideEffects:
201 if (!HasFoldFailureDiagnostic)
202 break;
203 // We've already failed to fold something. Keep that diagnostic.
204 [[fallthrough]];
205 case EvaluationMode::ConstantExpression:
206 case EvaluationMode::ConstantExpressionUnevaluated:
207 setActiveDiagnostic(false);
208 return true;
209 }
210 }
211 return false;
212}
213
215 uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
216 if (Limit != 0 && !stepsLeft())
217 return false;
218
219 switch (EvalMode) {
226 }
227 llvm_unreachable("Missed EvalMode case");
228}
229
231 switch (EvalMode) {
233 return true;
234
238 // By default, assume any side effect might be valid in some other
239 // evaluation of this expression from a different context.
242 }
243 llvm_unreachable("Missed EvalMode case");
244}
245
246bool State::keepEvaluatingAfterUndefinedBehavior() const {
247 switch (EvalMode) {
250 return true;
251
254 return checkingForUndefinedBehavior();
255 }
256 llvm_unreachable("Missed EvalMode case");
257}
Implements a partial diagnostic which may not be emitted.
A little helper class used to produce diagnostics.
This represents one expression.
Definition Expr.h:113
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
A partial diagnostic which we might know in advance that we are not going to emit.
Encodes a location in the source.
SourceLocation getBegin() const
Describes the statement/declaration an opcode was generated from.
Definition Source.h:77
SourceLocation getLoc() const
Definition Source.cpp:15
bool checkingForUndefinedBehavior() const
Are we checking an expression for overflow?
Definition State.h:126
EvaluationMode EvalMode
Definition State.h:193
virtual bool stepsLeft() const =0
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition State.cpp:86
DiagnosticBuilder report(SourceLocation Loc, diag::kind DiagId)
Directly reports a diagnostic message.
Definition State.cpp:103
bool emitRelaxedDiag(SourceLocation Loc, diag::kind DiagId)
If DiagId should be relaxed as per the current evaluation settings, emit it as a warning instead of a...
Definition State.cpp:20
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation could not be folded (FF => FoldFailure)
Definition State.cpp:37
Expr::EvalStatus & EvalStatus
Definition State.h:195
void addNotes(ArrayRef< PartialDiagnosticAt > Diags)
Add a stack of notes to a prior diagnostic.
Definition State.cpp:98
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:60
bool checkingPotentialConstantExpression() const
Are we checking whether the expression is a potential constant expression?
Definition State.h:122
bool keepEvaluatingAfterSideEffect() const
Should we continue evaluation after encountering a side-effect that we couldn't model?
Definition State.cpp:230
bool keepEvaluatingAfterFailure() const
Should we continue evaluation as much as possible after encountering a construct which can't be reduc...
Definition State.cpp:214
bool InConstantContext
Whether or not we're in a context where the front end requires a constant value.
Definition State.h:178
ASTContext & Ctx
Definition State.h:194
virtual ~State()
Definition State.cpp:18
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Top level wrappers for InstallAPI frontend operations.
@ ConstantFold
Fold the expression to a constant.
Definition State.h:67
@ ConstantExpressionUnevaluated
Evaluate as a constant expression.
Definition State.h:63
@ ConstantExpression
Evaluate as a constant expression.
Definition State.h:56
@ IgnoreSideEffects
Evaluate in any way we know how.
Definition State.h:71