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