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