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