Coverage Report

Created: 2024-01-17 10:31

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