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