1e5dd7070Spatrick //===--- State.cpp - State chain for the VM and AST Walker ------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick
9e5dd7070Spatrick #include "State.h"
10e5dd7070Spatrick #include "Frame.h"
11e5dd7070Spatrick #include "Program.h"
12e5dd7070Spatrick #include "clang/AST/ASTContext.h"
13e5dd7070Spatrick #include "clang/AST/CXXInheritance.h"
14e5dd7070Spatrick
15e5dd7070Spatrick using namespace clang;
16e5dd7070Spatrick using namespace clang::interp;
17e5dd7070Spatrick
~State()18e5dd7070Spatrick State::~State() {}
19e5dd7070Spatrick
FFDiag(SourceLocation Loc,diag::kind DiagId,unsigned ExtraNotes)20e5dd7070Spatrick OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId,
21e5dd7070Spatrick unsigned ExtraNotes) {
22e5dd7070Spatrick return diag(Loc, DiagId, ExtraNotes, false);
23e5dd7070Spatrick }
24e5dd7070Spatrick
FFDiag(const Expr * E,diag::kind DiagId,unsigned ExtraNotes)25e5dd7070Spatrick OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
26e5dd7070Spatrick unsigned ExtraNotes) {
27e5dd7070Spatrick if (getEvalStatus().Diag)
28e5dd7070Spatrick return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
29e5dd7070Spatrick setActiveDiagnostic(false);
30e5dd7070Spatrick return OptionalDiagnostic();
31e5dd7070Spatrick }
32e5dd7070Spatrick
FFDiag(const SourceInfo & SI,diag::kind DiagId,unsigned ExtraNotes)33e5dd7070Spatrick OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId,
34e5dd7070Spatrick unsigned ExtraNotes) {
35e5dd7070Spatrick if (getEvalStatus().Diag)
36e5dd7070Spatrick return diag(SI.getLoc(), DiagId, ExtraNotes, false);
37e5dd7070Spatrick setActiveDiagnostic(false);
38e5dd7070Spatrick return OptionalDiagnostic();
39e5dd7070Spatrick }
40e5dd7070Spatrick
CCEDiag(SourceLocation Loc,diag::kind DiagId,unsigned ExtraNotes)41e5dd7070Spatrick OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId,
42e5dd7070Spatrick unsigned ExtraNotes) {
43e5dd7070Spatrick // Don't override a previous diagnostic. Don't bother collecting
44e5dd7070Spatrick // diagnostics if we're evaluating for overflow.
45e5dd7070Spatrick if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()) {
46e5dd7070Spatrick setActiveDiagnostic(false);
47e5dd7070Spatrick return OptionalDiagnostic();
48e5dd7070Spatrick }
49e5dd7070Spatrick return diag(Loc, DiagId, ExtraNotes, true);
50e5dd7070Spatrick }
51e5dd7070Spatrick
CCEDiag(const Expr * E,diag::kind DiagId,unsigned ExtraNotes)52e5dd7070Spatrick OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId,
53e5dd7070Spatrick unsigned ExtraNotes) {
54e5dd7070Spatrick return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
55e5dd7070Spatrick }
56e5dd7070Spatrick
CCEDiag(const SourceInfo & SI,diag::kind DiagId,unsigned ExtraNotes)57e5dd7070Spatrick OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId,
58e5dd7070Spatrick unsigned ExtraNotes) {
59e5dd7070Spatrick return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
60e5dd7070Spatrick }
61e5dd7070Spatrick
Note(SourceLocation Loc,diag::kind DiagId)62e5dd7070Spatrick OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) {
63e5dd7070Spatrick if (!hasActiveDiagnostic())
64e5dd7070Spatrick return OptionalDiagnostic();
65e5dd7070Spatrick return OptionalDiagnostic(&addDiag(Loc, DiagId));
66e5dd7070Spatrick }
67e5dd7070Spatrick
addNotes(ArrayRef<PartialDiagnosticAt> Diags)68e5dd7070Spatrick void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
69e5dd7070Spatrick if (hasActiveDiagnostic()) {
70e5dd7070Spatrick getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(),
71e5dd7070Spatrick Diags.end());
72e5dd7070Spatrick }
73e5dd7070Spatrick }
74e5dd7070Spatrick
report(SourceLocation Loc,diag::kind DiagId)75e5dd7070Spatrick DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
76e5dd7070Spatrick return getCtx().getDiagnostics().Report(Loc, DiagId);
77e5dd7070Spatrick }
78e5dd7070Spatrick
79e5dd7070Spatrick /// Add a diagnostic to the diagnostics list.
addDiag(SourceLocation Loc,diag::kind DiagId)80e5dd7070Spatrick PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
81e5dd7070Spatrick PartialDiagnostic PD(DiagId, getCtx().getDiagAllocator());
82e5dd7070Spatrick getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
83e5dd7070Spatrick return getEvalStatus().Diag->back().second;
84e5dd7070Spatrick }
85e5dd7070Spatrick
diag(SourceLocation Loc,diag::kind DiagId,unsigned ExtraNotes,bool IsCCEDiag)86e5dd7070Spatrick OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
87e5dd7070Spatrick unsigned ExtraNotes, bool IsCCEDiag) {
88e5dd7070Spatrick Expr::EvalStatus &EvalStatus = getEvalStatus();
89e5dd7070Spatrick if (EvalStatus.Diag) {
90e5dd7070Spatrick if (hasPriorDiagnostic()) {
91e5dd7070Spatrick return OptionalDiagnostic();
92e5dd7070Spatrick }
93e5dd7070Spatrick
94e5dd7070Spatrick unsigned CallStackNotes = getCallStackDepth() - 1;
95e5dd7070Spatrick unsigned Limit = getCtx().getDiagnostics().getConstexprBacktraceLimit();
96e5dd7070Spatrick if (Limit)
97e5dd7070Spatrick CallStackNotes = std::min(CallStackNotes, Limit + 1);
98e5dd7070Spatrick if (checkingPotentialConstantExpression())
99e5dd7070Spatrick CallStackNotes = 0;
100e5dd7070Spatrick
101e5dd7070Spatrick setActiveDiagnostic(true);
102e5dd7070Spatrick setFoldFailureDiagnostic(!IsCCEDiag);
103e5dd7070Spatrick EvalStatus.Diag->clear();
104e5dd7070Spatrick EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
105e5dd7070Spatrick addDiag(Loc, DiagId);
106e5dd7070Spatrick if (!checkingPotentialConstantExpression()) {
107e5dd7070Spatrick addCallStack(Limit);
108e5dd7070Spatrick }
109e5dd7070Spatrick return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
110e5dd7070Spatrick }
111e5dd7070Spatrick setActiveDiagnostic(false);
112e5dd7070Spatrick return OptionalDiagnostic();
113e5dd7070Spatrick }
114e5dd7070Spatrick
getLangOpts() const115e5dd7070Spatrick const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); }
116e5dd7070Spatrick
addCallStack(unsigned Limit)117e5dd7070Spatrick void State::addCallStack(unsigned Limit) {
118e5dd7070Spatrick // Determine which calls to skip, if any.
119e5dd7070Spatrick unsigned ActiveCalls = getCallStackDepth() - 1;
120e5dd7070Spatrick unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart;
121e5dd7070Spatrick if (Limit && Limit < ActiveCalls) {
122e5dd7070Spatrick SkipStart = Limit / 2 + Limit % 2;
123e5dd7070Spatrick SkipEnd = ActiveCalls - Limit / 2;
124e5dd7070Spatrick }
125e5dd7070Spatrick
126e5dd7070Spatrick // Walk the call stack and add the diagnostics.
127e5dd7070Spatrick unsigned CallIdx = 0;
128e5dd7070Spatrick Frame *Top = getCurrentFrame();
129e5dd7070Spatrick const Frame *Bottom = getBottomFrame();
130e5dd7070Spatrick for (Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx) {
131e5dd7070Spatrick SourceLocation CallLocation = F->getCallLocation();
132e5dd7070Spatrick
133e5dd7070Spatrick // Skip this call?
134e5dd7070Spatrick if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
135e5dd7070Spatrick if (CallIdx == SkipStart) {
136e5dd7070Spatrick // Note that we're skipping calls.
137e5dd7070Spatrick addDiag(CallLocation, diag::note_constexpr_calls_suppressed)
138e5dd7070Spatrick << unsigned(ActiveCalls - Limit);
139e5dd7070Spatrick }
140e5dd7070Spatrick continue;
141e5dd7070Spatrick }
142e5dd7070Spatrick
143e5dd7070Spatrick // Use a different note for an inheriting constructor, because from the
144e5dd7070Spatrick // user's perspective it's not really a function at all.
145e5dd7070Spatrick if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(F->getCallee())) {
146e5dd7070Spatrick if (CD->isInheritingConstructor()) {
147e5dd7070Spatrick addDiag(CallLocation, diag::note_constexpr_inherited_ctor_call_here)
148e5dd7070Spatrick << CD->getParent();
149e5dd7070Spatrick continue;
150e5dd7070Spatrick }
151e5dd7070Spatrick }
152e5dd7070Spatrick
153*a9ac8606Spatrick SmallString<128> Buffer;
154e5dd7070Spatrick llvm::raw_svector_ostream Out(Buffer);
155e5dd7070Spatrick F->describe(Out);
156e5dd7070Spatrick addDiag(CallLocation, diag::note_constexpr_call_here) << Out.str();
157e5dd7070Spatrick }
158e5dd7070Spatrick }
159