annotate clang/lib/AST/Interp/State.cpp @ 176:de4ac79aef9d

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