clang 17.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"
14
15using namespace clang;
16using namespace clang::interp;
17
18State::~State() {}
19
21 unsigned ExtraNotes) {
22 return diag(Loc, DiagId, ExtraNotes, false);
23}
24
25OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
26 unsigned ExtraNotes) {
27 if (getEvalStatus().Diag)
28 return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
29 setActiveDiagnostic(false);
30 return OptionalDiagnostic();
31}
32
33OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId,
34 unsigned ExtraNotes) {
35 if (getEvalStatus().Diag)
36 return diag(SI.getLoc(), DiagId, ExtraNotes, false);
37 setActiveDiagnostic(false);
38 return OptionalDiagnostic();
39}
40
41OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId,
42 unsigned ExtraNotes) {
43 // Don't override a previous diagnostic. Don't bother collecting
44 // diagnostics if we're evaluating for overflow.
45 if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()) {
46 setActiveDiagnostic(false);
47 return OptionalDiagnostic();
48 }
49 return diag(Loc, DiagId, ExtraNotes, true);
50}
51
52OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId,
53 unsigned ExtraNotes) {
54 return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
55}
56
57OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId,
58 unsigned ExtraNotes) {
59 return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
60}
61
63 if (!hasActiveDiagnostic())
64 return OptionalDiagnostic();
65 return OptionalDiagnostic(&addDiag(Loc, DiagId));
66}
67
68void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
69 if (hasActiveDiagnostic()) {
70 getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(),
71 Diags.end());
72 }
73}
74
75DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
76 return getCtx().getDiagnostics().Report(Loc, DiagId);
77}
78
79/// Add a diagnostic to the diagnostics list.
80PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
81 PartialDiagnostic PD(DiagId, getCtx().getDiagAllocator());
82 getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
83 return getEvalStatus().Diag->back().second;
84}
85
86OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
87 unsigned ExtraNotes, bool IsCCEDiag) {
88 Expr::EvalStatus &EvalStatus = getEvalStatus();
89 if (EvalStatus.Diag) {
90 if (hasPriorDiagnostic()) {
91 return OptionalDiagnostic();
92 }
93
94 unsigned CallStackNotes = getCallStackDepth() - 1;
95 unsigned Limit = getCtx().getDiagnostics().getConstexprBacktraceLimit();
96 if (Limit)
97 CallStackNotes = std::min(CallStackNotes, Limit + 1);
98 if (checkingPotentialConstantExpression())
99 CallStackNotes = 0;
100
101 setActiveDiagnostic(true);
102 setFoldFailureDiagnostic(!IsCCEDiag);
103 EvalStatus.Diag->clear();
104 EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
105 addDiag(Loc, DiagId);
106 if (!checkingPotentialConstantExpression()) {
107 addCallStack(Limit);
108 }
109 return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
110 }
111 setActiveDiagnostic(false);
112 return OptionalDiagnostic();
113}
114
115const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); }
116
117void State::addCallStack(unsigned Limit) {
118 // Determine which calls to skip, if any.
119 unsigned ActiveCalls = getCallStackDepth() - 1;
120 unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart;
121 if (Limit && Limit < ActiveCalls) {
122 SkipStart = Limit / 2 + Limit % 2;
123 SkipEnd = ActiveCalls - Limit / 2;
124 }
125
126 // Walk the call stack and add the diagnostics.
127 unsigned CallIdx = 0;
128 Frame *Top = getCurrentFrame();
129 const Frame *Bottom = getBottomFrame();
130 for (Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx) {
131 SourceLocation CallLocation = F->getCallLocation();
132
133 // Skip this call?
134 if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
135 if (CallIdx == SkipStart) {
136 // Note that we're skipping calls.
137 addDiag(CallLocation, diag::note_constexpr_calls_suppressed)
138 << unsigned(ActiveCalls - Limit);
139 }
140 continue;
141 }
142
143 // Use a different note for an inheriting constructor, because from the
144 // user's perspective it's not really a function at all.
145 if (auto *CD = dyn_cast_if_present<CXXConstructorDecl>(F->getCallee())) {
146 if (CD->isInheritingConstructor()) {
147 addDiag(CallLocation, diag::note_constexpr_inherited_ctor_call_here)
148 << CD->getParent();
149 continue;
150 }
151 }
152
153 SmallString<128> Buffer;
154 llvm::raw_svector_ostream Out(Buffer);
155 F->describe(Out);
156 addDiag(CallLocation, diag::note_constexpr_call_here) << Out.str();
157 }
158}
Defines the clang::ASTContext interface.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
A little helper class used to produce diagnostics.
Definition: Diagnostic.h:1266
This represents one expression.
Definition: Expr.h:110
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:330
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:82
A partial diagnostic which we might know in advance that we are not going to emit.
Encodes a location in the source.
Base class for stack frames, shared between VM and walker.
Definition: Frame.h:25
virtual Frame * getCaller() const =0
Returns a pointer to the caller frame.
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:70
SourceLocation getLoc() const
Definition: Source.cpp:15
EvalStatus is a struct with detailed info about an evaluation in progress.
Definition: Expr.h:593
SmallVectorImpl< PartialDiagnosticAt > * Diag
Diag - If this is non-null, it will be filled in with a stack of notes indicating why evaluation fail...
Definition: Expr.h:610