clang  10.0.0svn
State.cpp
Go to the documentation of this file.
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"
14 
15 using namespace clang;
16 using namespace clang::interp;
17 
19 
21  unsigned ExtraNotes) {
22  return diag(Loc, DiagId, ExtraNotes, false);
23 }
24 
26  unsigned ExtraNotes) {
27  if (getEvalStatus().Diag)
28  return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
29  setActiveDiagnostic(false);
30  return OptionalDiagnostic();
31 }
32 
34  unsigned ExtraNotes) {
35  if (getEvalStatus().Diag)
36  return diag(SI.getLoc(), DiagId, ExtraNotes, false);
37  setActiveDiagnostic(false);
38  return OptionalDiagnostic();
39 }
40 
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 
53  unsigned ExtraNotes) {
54  return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
55 }
56 
58  unsigned ExtraNotes) {
59  return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
60 }
61 
63  if (!hasActiveDiagnostic())
64  return OptionalDiagnostic();
65  return OptionalDiagnostic(&addDiag(Loc, DiagId));
66 }
67 
69  if (hasActiveDiagnostic()) {
70  getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(),
71  Diags.end());
72  }
73 }
74 
76  return getCtx().getDiagnostics().Report(Loc, DiagId);
77 }
78 
79 /// Add a diagnostic to the diagnostics list.
80 PartialDiagnostic &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 
86 OptionalDiagnostic 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);
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);
107  addCallStack(Limit);
108  }
109  return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
110  }
111  setActiveDiagnostic(false);
112  return OptionalDiagnostic();
113 }
114 
115 const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); }
116 
117 void 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 }
virtual Expr::EvalStatus & getEvalStatus() const =0
Defines the clang::ASTContext interface.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
DiagnosticBuilder report(SourceLocation Loc, diag::kind DiagId)
Directly reports a diagnostic message.
Definition: State.cpp:75
DiagnosticsEngine & getDiagnostics() const
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1290
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:81
virtual Frame * getCaller() const =0
Returns a pointer to the caller frame.
virtual ASTContext & getCtx() const =0
virtual ~State()
Definition: State.cpp:18
SourceLocation getLoc() const
Definition: Source.cpp:15
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
SmallVectorImpl< PartialDiagnosticAt > * Diag
Diag - If this is non-null, it will be filled in with a stack of notes indicating why evaluation fail...
Definition: Expr.h:567
virtual unsigned getCallStackDepth()=0
A little helper class used to produce diagnostics.
Definition: Diagnostic.h:1043
virtual void setFoldFailureDiagnostic(bool Flag)=0
This represents one expression.
Definition: Expr.h:108
virtual bool hasActiveDiagnostic()=0
virtual void setActiveDiagnostic(bool Flag)=0
A partial diagnostic which we might know in advance that we are not going to emit.
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Definition: State.cpp:20
Base class for stack frames, shared between VM and walker.
Definition: Frame.h:25
virtual Frame * getCurrentFrame()=0
Encodes a location in the source.
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition: State.cpp:62
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:221
EvalStatus is a struct with detailed info about an evaluation in progress.
Definition: Expr.h:550
Dataflow Directional Tag Classes.
virtual bool checkingPotentialConstantExpression() const =0
void addNotes(ArrayRef< PartialDiagnosticAt > Diags)
Add a stack of notes to a prior diagnostic.
Definition: State.cpp:68
virtual bool hasPriorDiagnostic()=0
const LangOptions & getLangOpts() const
Definition: State.cpp:115
unsigned getConstexprBacktraceLimit() const
Retrieve the maximum number of constexpr evaluation notes to emit along with a given diagnostic...
Definition: Diagnostic.h:581
OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation does not produce a C++11 core constant expression.
Definition: State.cpp:41
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Definition: DiagnosticIDs.h:60
virtual const Frame * getBottomFrame() const =0
__DEVICE__ int min(int __a, int __b)
const LangOptions & getLangOpts() const
Definition: ASTContext.h:723