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