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