[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
//===--- State.cpp - State chain for the VM and AST Walker ------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "State.h"
|
|
|
|
#include "Frame.h"
|
|
|
|
#include "Program.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/CXXInheritance.h"
|
2023-05-04 07:09:24 +02:00
|
|
|
#include "clang/AST/OptionalDiagnostic.h"
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
using namespace clang::interp;
|
|
|
|
|
|
|
|
State::~State() {}
|
|
|
|
|
|
|
|
OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId,
|
|
|
|
unsigned ExtraNotes) {
|
|
|
|
return diag(Loc, DiagId, ExtraNotes, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
|
|
|
|
unsigned ExtraNotes) {
|
|
|
|
if (getEvalStatus().Diag)
|
|
|
|
return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
|
|
|
|
setActiveDiagnostic(false);
|
|
|
|
return OptionalDiagnostic();
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId,
|
|
|
|
unsigned ExtraNotes) {
|
|
|
|
if (getEvalStatus().Diag)
|
|
|
|
return diag(SI.getLoc(), DiagId, ExtraNotes, false);
|
|
|
|
setActiveDiagnostic(false);
|
|
|
|
return OptionalDiagnostic();
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId,
|
|
|
|
unsigned ExtraNotes) {
|
|
|
|
// Don't override a previous diagnostic. Don't bother collecting
|
|
|
|
// diagnostics if we're evaluating for overflow.
|
|
|
|
if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()) {
|
|
|
|
setActiveDiagnostic(false);
|
|
|
|
return OptionalDiagnostic();
|
|
|
|
}
|
|
|
|
return diag(Loc, DiagId, ExtraNotes, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId,
|
|
|
|
unsigned ExtraNotes) {
|
|
|
|
return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId,
|
|
|
|
unsigned ExtraNotes) {
|
|
|
|
return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) {
|
|
|
|
if (!hasActiveDiagnostic())
|
|
|
|
return OptionalDiagnostic();
|
|
|
|
return OptionalDiagnostic(&addDiag(Loc, DiagId));
|
|
|
|
}
|
|
|
|
|
|
|
|
void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
|
|
|
|
if (hasActiveDiagnostic()) {
|
|
|
|
getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(),
|
|
|
|
Diags.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
|
2024-08-26 22:23:07 +08:00
|
|
|
return getASTContext().getDiagnostics().Report(Loc, DiagId);
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Add a diagnostic to the diagnostics list.
|
|
|
|
PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
|
2024-08-26 22:23:07 +08:00
|
|
|
PartialDiagnostic PD(DiagId, getASTContext().getDiagAllocator());
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
|
|
|
|
return getEvalStatus().Diag->back().second;
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
|
|
|
|
unsigned ExtraNotes, bool IsCCEDiag) {
|
|
|
|
Expr::EvalStatus &EvalStatus = getEvalStatus();
|
|
|
|
if (EvalStatus.Diag) {
|
|
|
|
if (hasPriorDiagnostic()) {
|
|
|
|
return OptionalDiagnostic();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned CallStackNotes = getCallStackDepth() - 1;
|
2024-08-26 22:23:07 +08:00
|
|
|
unsigned Limit =
|
|
|
|
getASTContext().getDiagnostics().getConstexprBacktraceLimit();
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
if (Limit)
|
|
|
|
CallStackNotes = std::min(CallStackNotes, Limit + 1);
|
|
|
|
if (checkingPotentialConstantExpression())
|
|
|
|
CallStackNotes = 0;
|
|
|
|
|
|
|
|
setActiveDiagnostic(true);
|
|
|
|
setFoldFailureDiagnostic(!IsCCEDiag);
|
|
|
|
EvalStatus.Diag->clear();
|
|
|
|
EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
|
|
|
|
addDiag(Loc, DiagId);
|
|
|
|
if (!checkingPotentialConstantExpression()) {
|
|
|
|
addCallStack(Limit);
|
|
|
|
}
|
|
|
|
return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
|
|
|
|
}
|
|
|
|
setActiveDiagnostic(false);
|
|
|
|
return OptionalDiagnostic();
|
|
|
|
}
|
|
|
|
|
2024-08-26 22:23:07 +08:00
|
|
|
const LangOptions &State::getLangOpts() const {
|
|
|
|
return getASTContext().getLangOpts();
|
|
|
|
}
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
|
|
|
|
void State::addCallStack(unsigned Limit) {
|
|
|
|
// Determine which calls to skip, if any.
|
|
|
|
unsigned ActiveCalls = getCallStackDepth() - 1;
|
|
|
|
unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart;
|
|
|
|
if (Limit && Limit < ActiveCalls) {
|
|
|
|
SkipStart = Limit / 2 + Limit % 2;
|
|
|
|
SkipEnd = ActiveCalls - Limit / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Walk the call stack and add the diagnostics.
|
|
|
|
unsigned CallIdx = 0;
|
2023-07-08 10:47:29 +02:00
|
|
|
const Frame *Top = getCurrentFrame();
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
const Frame *Bottom = getBottomFrame();
|
2023-07-08 10:47:29 +02:00
|
|
|
for (const Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx) {
|
2023-08-01 11:39:06 +02:00
|
|
|
SourceRange CallRange = F->getCallRange();
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
|
|
|
|
// Skip this call?
|
|
|
|
if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
|
|
|
|
if (CallIdx == SkipStart) {
|
|
|
|
// Note that we're skipping calls.
|
2023-08-01 11:39:06 +02:00
|
|
|
addDiag(CallRange.getBegin(), diag::note_constexpr_calls_suppressed)
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
<< unsigned(ActiveCalls - Limit);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use a different note for an inheriting constructor, because from the
|
|
|
|
// user's perspective it's not really a function at all.
|
2023-04-19 08:10:13 +02:00
|
|
|
if (const auto *CD =
|
|
|
|
dyn_cast_if_present<CXXConstructorDecl>(F->getCallee());
|
|
|
|
CD && CD->isInheritingConstructor()) {
|
2023-08-01 11:39:06 +02:00
|
|
|
addDiag(CallRange.getBegin(),
|
|
|
|
diag::note_constexpr_inherited_ctor_call_here)
|
2023-04-19 08:10:13 +02:00
|
|
|
<< CD->getParent();
|
|
|
|
continue;
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 13:02:58 +00:00
|
|
|
SmallString<128> Buffer;
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
llvm::raw_svector_ostream Out(Buffer);
|
|
|
|
F->describe(Out);
|
2024-04-16 07:52:39 +02:00
|
|
|
if (!Buffer.empty())
|
|
|
|
addDiag(CallRange.getBegin(), diag::note_constexpr_call_here)
|
|
|
|
<< Out.str() << CallRange;
|
[Clang Interpreter] Initial patch for the constexpr interpreter
Summary:
This patch introduces the skeleton of the constexpr interpreter,
capable of evaluating a simple constexpr functions consisting of
if statements. The interpreter is described in more detail in the
RFC. Further patches will add more features.
Reviewers: Bigcheese, jfb, rsmith
Subscribers: bruno, uenoku, ldionne, Tyker, thegameg, tschuett, dexonsmith, mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64146
llvm-svn: 371834
2019-09-13 09:46:16 +00:00
|
|
|
}
|
|
|
|
}
|