Home | History | Annotate | Line # | Download | only in Interp
      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-exception
      6 //
      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 
     15 using namespace clang;
     16 using namespace clang::interp;
     17 
     18 State::~State() {}
     19 
     20 OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId,
     21                                  unsigned ExtraNotes) {
     22   return diag(Loc, DiagId, ExtraNotes, false);
     23 }
     24 
     25 OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
     26                                  unsigned ExtraNotes) {
     27   if (getEvalStatus().Diag)
     28     return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
     29   setActiveDiagnostic(false);
     30   return OptionalDiagnostic();
     31 }
     32 
     33 OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId,
     34                                  unsigned ExtraNotes) {
     35   if (getEvalStatus().Diag)
     36     return diag(SI.getLoc(), DiagId, ExtraNotes, false);
     37   setActiveDiagnostic(false);
     38   return OptionalDiagnostic();
     39 }
     40 
     41 OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId,
     42                                   unsigned ExtraNotes) {
     43   // Don't override a previous diagnostic. Don't bother collecting
     44   // diagnostics if we're evaluating for overflow.
     45   if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()) {
     46     setActiveDiagnostic(false);
     47     return OptionalDiagnostic();
     48   }
     49   return diag(Loc, DiagId, ExtraNotes, true);
     50 }
     51 
     52 OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId,
     53                                   unsigned ExtraNotes) {
     54   return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
     55 }
     56 
     57 OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId,
     58                                   unsigned ExtraNotes) {
     59   return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
     60 }
     61 
     62 OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) {
     63   if (!hasActiveDiagnostic())
     64     return OptionalDiagnostic();
     65   return OptionalDiagnostic(&addDiag(Loc, DiagId));
     66 }
     67 
     68 void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
     69   if (hasActiveDiagnostic()) {
     70     getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(),
     71                                  Diags.end());
     72   }
     73 }
     74 
     75 DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
     76   return getCtx().getDiagnostics().Report(Loc, DiagId);
     77 }
     78 
     79 /// Add a diagnostic to the diagnostics list.
     80 PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
     81   PartialDiagnostic PD(DiagId, getCtx().getDiagAllocator());
     82   getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
     83   return getEvalStatus().Diag->back().second;
     84 }
     85 
     86 OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
     87                                unsigned ExtraNotes, bool IsCCEDiag) {
     88   Expr::EvalStatus &EvalStatus = getEvalStatus();
     89   if (EvalStatus.Diag) {
     90     if (hasPriorDiagnostic()) {
     91       return OptionalDiagnostic();
     92     }
     93 
     94     unsigned CallStackNotes = getCallStackDepth() - 1;
     95     unsigned Limit = getCtx().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 
    115 const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); }
    116 
    117 void State::addCallStack(unsigned Limit) {
    118   // Determine which calls to skip, if any.
    119   unsigned ActiveCalls = getCallStackDepth() - 1;
    120   unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart;
    121   if (Limit && Limit < ActiveCalls) {
    122     SkipStart = Limit / 2 + Limit % 2;
    123     SkipEnd = ActiveCalls - Limit / 2;
    124   }
    125 
    126   // Walk the call stack and add the diagnostics.
    127   unsigned CallIdx = 0;
    128   Frame *Top = getCurrentFrame();
    129   const Frame *Bottom = getBottomFrame();
    130   for (Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx) {
    131     SourceLocation CallLocation = F->getCallLocation();
    132 
    133     // Skip this call?
    134     if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
    135       if (CallIdx == SkipStart) {
    136         // Note that we're skipping calls.
    137         addDiag(CallLocation, diag::note_constexpr_calls_suppressed)
    138             << unsigned(ActiveCalls - Limit);
    139       }
    140       continue;
    141     }
    142 
    143     // Use a different note for an inheriting constructor, because from the
    144     // user's perspective it's not really a function at all.
    145     if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(F->getCallee())) {
    146       if (CD->isInheritingConstructor()) {
    147         addDiag(CallLocation, diag::note_constexpr_inherited_ctor_call_here)
    148             << CD->getParent();
    149         continue;
    150       }
    151     }
    152 
    153     SmallString<128> Buffer;
    154     llvm::raw_svector_ostream Out(Buffer);
    155     F->describe(Out);
    156     addDiag(CallLocation, diag::note_constexpr_call_here) << Out.str();
    157   }
    158 }
    159