/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/State.cpp
Line | Count | Source (jump to first uncovered line) |
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" |
12 | | #include "clang/AST/ASTContext.h" |
13 | | #include "clang/AST/CXXInheritance.h" |
14 | | |
15 | | using namespace clang; |
16 | | using namespace clang::interp; |
17 | | |
18 | 20.7M | State::~State() {} |
19 | | |
20 | | OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId, |
21 | 128k | unsigned ExtraNotes) { |
22 | 128k | return diag(Loc, DiagId, ExtraNotes, false); |
23 | 128k | } |
24 | | |
25 | | OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId, |
26 | 6.36M | unsigned ExtraNotes) { |
27 | 6.36M | if (getEvalStatus().Diag) |
28 | 749k | return diag(E->getExprLoc(), DiagId, ExtraNotes, false); |
29 | 5.61M | setActiveDiagnostic(false); |
30 | 5.61M | return OptionalDiagnostic(); |
31 | 6.36M | } |
32 | | |
33 | | OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId, |
34 | 0 | unsigned ExtraNotes) { |
35 | 0 | if (getEvalStatus().Diag) |
36 | 0 | return diag(SI.getLoc(), DiagId, ExtraNotes, false); |
37 | 0 | setActiveDiagnostic(false); |
38 | 0 | return OptionalDiagnostic(); |
39 | 0 | } |
40 | | |
41 | | OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId, |
42 | 38.0k | unsigned ExtraNotes) { |
43 | | // Don't override a previous diagnostic. Don't bother collecting |
44 | | // diagnostics if we're evaluating for overflow. |
45 | 38.0k | if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()8.33k ) { |
46 | 30.5k | setActiveDiagnostic(false); |
47 | 30.5k | return OptionalDiagnostic(); |
48 | 30.5k | } |
49 | 7.51k | return diag(Loc, DiagId, ExtraNotes, true); |
50 | 38.0k | } |
51 | | |
52 | | OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId, |
53 | 36.1k | unsigned ExtraNotes) { |
54 | 36.1k | return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes); |
55 | 36.1k | } |
56 | | |
57 | | OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId, |
58 | 0 | unsigned ExtraNotes) { |
59 | 0 | return CCEDiag(SI.getLoc(), DiagId, ExtraNotes); |
60 | 0 | } |
61 | | |
62 | 4.72M | OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) { |
63 | 4.72M | if (!hasActiveDiagnostic()) |
64 | 3.94M | return OptionalDiagnostic(); |
65 | 776k | return OptionalDiagnostic(&addDiag(Loc, DiagId)); |
66 | 4.72M | } |
67 | | |
68 | 0 | void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) { |
69 | 0 | if (hasActiveDiagnostic()) { |
70 | 0 | getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(), |
71 | 0 | Diags.end()); |
72 | 0 | } |
73 | 0 | } |
74 | | |
75 | 108 | DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) { |
76 | 108 | return getCtx().getDiagnostics().Report(Loc, DiagId); |
77 | 108 | } |
78 | | |
79 | | /// Add a diagnostic to the diagnostics list. |
80 | 1.60M | PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) { |
81 | 1.60M | PartialDiagnostic PD(DiagId, getCtx().getDiagAllocator()); |
82 | 1.60M | getEvalStatus().Diag->push_back(std::make_pair(Loc, PD)); |
83 | 1.60M | return getEvalStatus().Diag->back().second; |
84 | 1.60M | } |
85 | | |
86 | | OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId, |
87 | 885k | unsigned ExtraNotes, bool IsCCEDiag) { |
88 | 885k | Expr::EvalStatus &EvalStatus = getEvalStatus(); |
89 | 885k | if (EvalStatus.Diag) { |
90 | 826k | if (hasPriorDiagnostic()) { |
91 | 4.20k | return OptionalDiagnostic(); |
92 | 4.20k | } |
93 | | |
94 | 822k | unsigned CallStackNotes = getCallStackDepth() - 1; |
95 | 822k | unsigned Limit = getCtx().getDiagnostics().getConstexprBacktraceLimit(); |
96 | 822k | if (Limit) |
97 | 819k | CallStackNotes = std::min(CallStackNotes, Limit + 1); |
98 | 822k | if (checkingPotentialConstantExpression()) |
99 | 352 | CallStackNotes = 0; |
100 | | |
101 | 822k | setActiveDiagnostic(true); |
102 | 822k | setFoldFailureDiagnostic(!IsCCEDiag); |
103 | 822k | EvalStatus.Diag->clear(); |
104 | 822k | EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes); |
105 | 822k | addDiag(Loc, DiagId); |
106 | 822k | if (!checkingPotentialConstantExpression()) { |
107 | 822k | addCallStack(Limit); |
108 | 822k | } |
109 | 822k | return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second); |
110 | 826k | } |
111 | 59.0k | setActiveDiagnostic(false); |
112 | 59.0k | return OptionalDiagnostic(); |
113 | 885k | } |
114 | | |
115 | 26.6M | const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); } |
116 | | |
117 | 822k | void State::addCallStack(unsigned Limit) { |
118 | | // Determine which calls to skip, if any. |
119 | 822k | unsigned ActiveCalls = getCallStackDepth() - 1; |
120 | 822k | unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart; |
121 | 822k | if (Limit && Limit < ActiveCalls819k ) { |
122 | 8 | SkipStart = Limit / 2 + Limit % 2; |
123 | 8 | SkipEnd = ActiveCalls - Limit / 2; |
124 | 8 | } |
125 | | |
126 | | // Walk the call stack and add the diagnostics. |
127 | 822k | unsigned CallIdx = 0; |
128 | 822k | Frame *Top = getCurrentFrame(); |
129 | 822k | const Frame *Bottom = getBottomFrame(); |
130 | 825k | for (Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx3.13k ) { |
131 | 3.13k | SourceLocation CallLocation = F->getCallLocation(); |
132 | | |
133 | | // Skip this call? |
134 | 3.13k | if (CallIdx >= SkipStart && CallIdx < SkipEnd746 ) { |
135 | 714 | if (CallIdx == SkipStart) { |
136 | | // Note that we're skipping calls. |
137 | 8 | addDiag(CallLocation, diag::note_constexpr_calls_suppressed) |
138 | 8 | << unsigned(ActiveCalls - Limit); |
139 | 8 | } |
140 | 714 | continue; |
141 | 714 | } |
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 | 2.42k | if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(F->getCallee())) { |
146 | 473 | if (CD->isInheritingConstructor()) { |
147 | 0 | addDiag(CallLocation, diag::note_constexpr_inherited_ctor_call_here) |
148 | 0 | << CD->getParent(); |
149 | 0 | continue; |
150 | 0 | } |
151 | 473 | } |
152 | | |
153 | 2.42k | SmallString<128> Buffer; |
154 | 2.42k | llvm::raw_svector_ostream Out(Buffer); |
155 | 2.42k | F->describe(Out); |
156 | 2.42k | addDiag(CallLocation, diag::note_constexpr_call_here) << Out.str(); |
157 | 2.42k | } |
158 | 822k | } |