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