1353942Sdim//===--- State.cpp - State chain for the VM and AST Walker ------*- C++ -*-===// 2353942Sdim// 3353942Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353942Sdim// See https://llvm.org/LICENSE.txt for license information. 5353942Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353942Sdim// 7353942Sdim//===----------------------------------------------------------------------===// 8353942Sdim 9353942Sdim#include "State.h" 10353942Sdim#include "Frame.h" 11353942Sdim#include "Program.h" 12353942Sdim#include "clang/AST/ASTContext.h" 13353942Sdim#include "clang/AST/CXXInheritance.h" 14353942Sdim 15353942Sdimusing namespace clang; 16353942Sdimusing namespace clang::interp; 17353942Sdim 18353942SdimState::~State() {} 19353942Sdim 20353942SdimOptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId, 21353942Sdim unsigned ExtraNotes) { 22353942Sdim return diag(Loc, DiagId, ExtraNotes, false); 23353942Sdim} 24353942Sdim 25353942SdimOptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId, 26353942Sdim unsigned ExtraNotes) { 27353942Sdim if (getEvalStatus().Diag) 28353942Sdim return diag(E->getExprLoc(), DiagId, ExtraNotes, false); 29353942Sdim setActiveDiagnostic(false); 30353942Sdim return OptionalDiagnostic(); 31353942Sdim} 32353942Sdim 33353942SdimOptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId, 34353942Sdim unsigned ExtraNotes) { 35353942Sdim if (getEvalStatus().Diag) 36353942Sdim return diag(SI.getLoc(), DiagId, ExtraNotes, false); 37353942Sdim setActiveDiagnostic(false); 38353942Sdim return OptionalDiagnostic(); 39353942Sdim} 40353942Sdim 41353942SdimOptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId, 42353942Sdim unsigned ExtraNotes) { 43353942Sdim // Don't override a previous diagnostic. Don't bother collecting 44353942Sdim // diagnostics if we're evaluating for overflow. 45353942Sdim if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()) { 46353942Sdim setActiveDiagnostic(false); 47353942Sdim return OptionalDiagnostic(); 48353942Sdim } 49353942Sdim return diag(Loc, DiagId, ExtraNotes, true); 50353942Sdim} 51353942Sdim 52353942SdimOptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId, 53353942Sdim unsigned ExtraNotes) { 54353942Sdim return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes); 55353942Sdim} 56353942Sdim 57353942SdimOptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId, 58353942Sdim unsigned ExtraNotes) { 59353942Sdim return CCEDiag(SI.getLoc(), DiagId, ExtraNotes); 60353942Sdim} 61353942Sdim 62353942SdimOptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) { 63353942Sdim if (!hasActiveDiagnostic()) 64353942Sdim return OptionalDiagnostic(); 65353942Sdim return OptionalDiagnostic(&addDiag(Loc, DiagId)); 66353942Sdim} 67353942Sdim 68353942Sdimvoid State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) { 69353942Sdim if (hasActiveDiagnostic()) { 70353942Sdim getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(), 71353942Sdim Diags.end()); 72353942Sdim } 73353942Sdim} 74353942Sdim 75353942SdimDiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) { 76353942Sdim return getCtx().getDiagnostics().Report(Loc, DiagId); 77353942Sdim} 78353942Sdim 79353942Sdim/// Add a diagnostic to the diagnostics list. 80353942SdimPartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) { 81353942Sdim PartialDiagnostic PD(DiagId, getCtx().getDiagAllocator()); 82353942Sdim getEvalStatus().Diag->push_back(std::make_pair(Loc, PD)); 83353942Sdim return getEvalStatus().Diag->back().second; 84353942Sdim} 85353942Sdim 86353942SdimOptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId, 87353942Sdim unsigned ExtraNotes, bool IsCCEDiag) { 88353942Sdim Expr::EvalStatus &EvalStatus = getEvalStatus(); 89353942Sdim if (EvalStatus.Diag) { 90353942Sdim if (hasPriorDiagnostic()) { 91353942Sdim return OptionalDiagnostic(); 92353942Sdim } 93353942Sdim 94353942Sdim unsigned CallStackNotes = getCallStackDepth() - 1; 95353942Sdim unsigned Limit = getCtx().getDiagnostics().getConstexprBacktraceLimit(); 96353942Sdim if (Limit) 97353942Sdim CallStackNotes = std::min(CallStackNotes, Limit + 1); 98353942Sdim if (checkingPotentialConstantExpression()) 99353942Sdim CallStackNotes = 0; 100353942Sdim 101353942Sdim setActiveDiagnostic(true); 102353942Sdim setFoldFailureDiagnostic(!IsCCEDiag); 103353942Sdim EvalStatus.Diag->clear(); 104353942Sdim EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes); 105353942Sdim addDiag(Loc, DiagId); 106353942Sdim if (!checkingPotentialConstantExpression()) { 107353942Sdim addCallStack(Limit); 108353942Sdim } 109353942Sdim return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second); 110353942Sdim } 111353942Sdim setActiveDiagnostic(false); 112353942Sdim return OptionalDiagnostic(); 113353942Sdim} 114353942Sdim 115353942Sdimconst LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); } 116353942Sdim 117353942Sdimvoid State::addCallStack(unsigned Limit) { 118353942Sdim // Determine which calls to skip, if any. 119353942Sdim unsigned ActiveCalls = getCallStackDepth() - 1; 120353942Sdim unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart; 121353942Sdim if (Limit && Limit < ActiveCalls) { 122353942Sdim SkipStart = Limit / 2 + Limit % 2; 123353942Sdim SkipEnd = ActiveCalls - Limit / 2; 124353942Sdim } 125353942Sdim 126353942Sdim // Walk the call stack and add the diagnostics. 127353942Sdim unsigned CallIdx = 0; 128353942Sdim Frame *Top = getCurrentFrame(); 129353942Sdim const Frame *Bottom = getBottomFrame(); 130353942Sdim for (Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx) { 131353942Sdim SourceLocation CallLocation = F->getCallLocation(); 132353942Sdim 133353942Sdim // Skip this call? 134353942Sdim if (CallIdx >= SkipStart && CallIdx < SkipEnd) { 135353942Sdim if (CallIdx == SkipStart) { 136353942Sdim // Note that we're skipping calls. 137353942Sdim addDiag(CallLocation, diag::note_constexpr_calls_suppressed) 138353942Sdim << unsigned(ActiveCalls - Limit); 139353942Sdim } 140353942Sdim continue; 141353942Sdim } 142353942Sdim 143353942Sdim // Use a different note for an inheriting constructor, because from the 144353942Sdim // user's perspective it's not really a function at all. 145353942Sdim if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(F->getCallee())) { 146353942Sdim if (CD->isInheritingConstructor()) { 147353942Sdim addDiag(CallLocation, diag::note_constexpr_inherited_ctor_call_here) 148353942Sdim << CD->getParent(); 149353942Sdim continue; 150353942Sdim } 151353942Sdim } 152353942Sdim 153353942Sdim SmallVector<char, 128> Buffer; 154353942Sdim llvm::raw_svector_ostream Out(Buffer); 155353942Sdim F->describe(Out); 156353942Sdim addDiag(CallLocation, diag::note_constexpr_call_here) << Out.str(); 157353942Sdim } 158353942Sdim} 159