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