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