150
|
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 State::~State() {}
|
|
19
|
|
20 OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId,
|
|
21 unsigned ExtraNotes) {
|
|
22 return diag(Loc, DiagId, ExtraNotes, false);
|
|
23 }
|
|
24
|
|
25 OptionalDiagnostic 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
|
|
33 OptionalDiagnostic 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
|
|
41 OptionalDiagnostic 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
|
|
52 OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId,
|
|
53 unsigned ExtraNotes) {
|
|
54 return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
|
|
55 }
|
|
56
|
|
57 OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId,
|
|
58 unsigned ExtraNotes) {
|
|
59 return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
|
|
60 }
|
|
61
|
|
62 OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) {
|
|
63 if (!hasActiveDiagnostic())
|
|
64 return OptionalDiagnostic();
|
|
65 return OptionalDiagnostic(&addDiag(Loc, DiagId));
|
|
66 }
|
|
67
|
|
68 void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
|
|
69 if (hasActiveDiagnostic()) {
|
|
70 getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(),
|
|
71 Diags.end());
|
|
72 }
|
|
73 }
|
|
74
|
|
75 DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
|
|
76 return getCtx().getDiagnostics().Report(Loc, DiagId);
|
|
77 }
|
|
78
|
|
79 /// Add a diagnostic to the diagnostics list.
|
|
80 PartialDiagnostic &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
|
|
86 OptionalDiagnostic 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
|
|
115 const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); }
|
|
116
|
|
117 void 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_or_null<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 SmallVector<char, 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 }
|