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