brintos

brintos / llvm-project-archived public Read only

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