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 15 using namespace clang; 16 using namespace clang::interp; 17 18 State::~State() {} 19 20 OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId, 21 unsigned ExtraNotes) { 22 return diag(Loc, DiagId, ExtraNotes, false); 23 } 24 25 OptionalDiagnostic 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 33 OptionalDiagnostic 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 41 OptionalDiagnostic 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 52 OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId, 53 unsigned ExtraNotes) { 54 return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes); 55 } 56 57 OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId, 58 unsigned ExtraNotes) { 59 return CCEDiag(SI.getLoc(), DiagId, ExtraNotes); 60 } 61 62 OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) { 63 if (!hasActiveDiagnostic()) 64 return OptionalDiagnostic(); 65 return OptionalDiagnostic(&addDiag(Loc, DiagId)); 66 } 67 68 void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) { 69 if (hasActiveDiagnostic()) { 70 getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(), 71 Diags.end()); 72 } 73 } 74 75 DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) { 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); 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 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 SmallString<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