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