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