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