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