[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
|
|
|
//===--- Interp.h - Interpreter for the constexpr VM ------------*- 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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Definition of the interpreter state and entry point.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
|
|
|
|
#define LLVM_CLANG_AST_INTERP_INTERP_H
|
|
|
|
|
2024-06-17 16:07:58 +02:00
|
|
|
#include "../ExprConstShared.h"
|
2023-01-21 19:32:02 +01:00
|
|
|
#include "Boolean.h"
|
2024-07-15 13:19:33 +02:00
|
|
|
#include "DynamicAllocator.h"
|
2023-01-25 14:51:16 +01:00
|
|
|
#include "Floating.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
|
|
|
#include "Function.h"
|
2023-01-11 12:12:52 +01:00
|
|
|
#include "FunctionPointer.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
|
|
|
#include "InterpFrame.h"
|
|
|
|
#include "InterpStack.h"
|
|
|
|
#include "InterpState.h"
|
2024-06-06 11:17:48 +02:00
|
|
|
#include "MemberPointer.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
|
|
|
#include "Opcode.h"
|
|
|
|
#include "PrimType.h"
|
|
|
|
#include "Program.h"
|
|
|
|
#include "State.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/Expr.h"
|
|
|
|
#include "llvm/ADT/APFloat.h"
|
|
|
|
#include "llvm/ADT/APSInt.h"
|
[Clang interpreter] Avoid storing pointers at unaligned locations
The Clang interpreter's bytecode uses a packed stream of bytes
representation, but also wants to have some opcodes take pointers as
arguments, which are currently embedded in the bytecode directly.
However, CHERI, and thus Arm's upcoming experimental Morello prototype,
provide spatial memory safety for C/C++ by implementing language-level
(and sub-language-level) pointers as capabilities, which track bounds,
permissions and validity in hardware. This uses tagged memory with a
single tag bit at every capability-aligned address, and so storing
pointers to unaligned addresses results in the tag being stripped,
leading to a tag fault when the pointer is ultimately dereferenced at a
later point.
In order to support a stricter C/C++ implementation like CHERI, we no
longer store pointers directly in the bytecode, instead storing them in
a table and embedding the index in the bytecode.
Reviewed By: nand
Differential Revision: https://reviews.llvm.org/D97606
2021-07-28 14:49:37 +01:00
|
|
|
#include <type_traits>
|
[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
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace interp {
|
|
|
|
|
|
|
|
using APSInt = llvm::APSInt;
|
|
|
|
|
2021-08-31 12:31:24 +05:30
|
|
|
/// Convert a value to an APValue.
|
2024-07-20 15:25:00 +02:00
|
|
|
template <typename T>
|
|
|
|
bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
|
|
|
|
R = V.toAPValue(S.getCtx());
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks if the variable has externally defined storage.
|
|
|
|
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if the array is offsetable.
|
|
|
|
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
2021-08-31 12:31:24 +05:30
|
|
|
/// Checks if a pointer is live and accessible.
|
[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
|
|
|
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
AccessKinds AK);
|
2023-10-26 15:15:25 +02:00
|
|
|
|
|
|
|
/// Checks if a pointer is a dummy pointer.
|
2024-05-24 16:23:56 +02:00
|
|
|
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
AccessKinds AK);
|
2023-10-26 15:15:25 +02:00
|
|
|
|
[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
|
|
|
/// Checks if a pointer is null.
|
|
|
|
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
CheckSubobjectKind CSK);
|
|
|
|
|
|
|
|
/// Checks if a pointer is in range.
|
|
|
|
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
AccessKinds AK);
|
|
|
|
|
|
|
|
/// Checks if a field from which a pointer is going to be derived is valid.
|
|
|
|
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
CheckSubobjectKind CSK);
|
|
|
|
|
2023-04-25 14:30:28 +02:00
|
|
|
/// Checks if Ptr is a one-past-the-end pointer.
|
|
|
|
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
CheckSubobjectKind CSK);
|
2023-04-24 16:45:16 +02:00
|
|
|
|
2024-06-06 11:17:48 +02:00
|
|
|
/// Checks if the dowcast using the given offset is possible with the given
|
|
|
|
/// pointer.
|
|
|
|
bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
uint32_t Offset);
|
|
|
|
|
[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
|
|
|
/// Checks if a pointer points to const storage.
|
|
|
|
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
2024-01-13 05:51:03 +01:00
|
|
|
/// Checks if the Descriptor is of a constexpr or const global variable.
|
|
|
|
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
|
|
|
|
|
[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
|
|
|
/// Checks if a pointer points to a mutable field.
|
|
|
|
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a value can be loaded from a block.
|
2024-06-29 06:57:26 +02:00
|
|
|
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
AccessKinds AK = AK_Read);
|
[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
|
|
|
|
2023-05-04 15:31:24 +02:00
|
|
|
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
AccessKinds AK);
|
2024-01-31 08:03:37 +01:00
|
|
|
/// Check if a global variable is initialized.
|
|
|
|
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
2023-05-04 15:31:24 +02:00
|
|
|
|
[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
|
|
|
/// Checks if a value can be stored in a block.
|
|
|
|
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a method can be invoked on an object.
|
|
|
|
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a value can be initialized.
|
|
|
|
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
|
|
|
|
|
|
|
|
/// Checks if a method can be called.
|
2022-10-28 10:31:47 +02:00
|
|
|
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
|
[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
|
|
|
|
2023-04-17 15:23:37 +02:00
|
|
|
/// Checks if calling the currently active function would exceed
|
|
|
|
/// the allowed call depth.
|
|
|
|
bool CheckCallDepth(InterpState &S, CodePtr OpPC);
|
|
|
|
|
[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
|
|
|
/// Checks the 'this' pointer.
|
|
|
|
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
|
|
|
|
|
|
|
|
/// Checks if a method is pure virtual.
|
|
|
|
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
|
|
|
|
|
2024-02-25 14:03:47 +01:00
|
|
|
/// Checks if all the arguments annotated as 'nonnull' are in fact not null.
|
|
|
|
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
|
|
|
|
const CallExpr *CE, unsigned ArgSize);
|
|
|
|
|
2024-07-15 13:19:33 +02:00
|
|
|
/// Checks if dynamic memory allocation is available in the current
|
|
|
|
/// language mode.
|
|
|
|
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
|
|
|
|
|
|
|
|
/// Diagnose mismatched new[]/delete or new/delete[] pairs.
|
|
|
|
bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
|
|
|
|
bool DeleteIsArray, const Descriptor *D,
|
|
|
|
const Expr *NewExpr);
|
|
|
|
|
|
|
|
/// Check the source of the pointer passed to delete/delete[] has actually
|
|
|
|
/// been heap allocated by us.
|
|
|
|
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
|
|
|
|
const Pointer &Ptr);
|
|
|
|
|
2023-09-29 09:41:58 +02:00
|
|
|
/// Sets the given integral value to the pointer, which is of
|
|
|
|
/// a std::{weak,partial,strong}_ordering type.
|
|
|
|
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
|
|
|
|
const Pointer &Ptr, const APSInt &IntValue);
|
|
|
|
|
2024-03-12 15:27:35 +01:00
|
|
|
/// Copy the contents of Src into Dest.
|
|
|
|
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
|
|
|
|
|
2023-01-19 13:24:40 +01:00
|
|
|
/// Checks if the shift operation is legal.
|
2023-05-09 19:38:37 +02:00
|
|
|
template <typename LT, typename RT>
|
|
|
|
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
|
|
|
|
unsigned Bits) {
|
2023-01-19 13:24:40 +01:00
|
|
|
if (RHS.isNegative()) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
|
2024-07-24 12:36:08 -07:00
|
|
|
if (!S.noteUndefinedBehavior())
|
|
|
|
return false;
|
2023-01-19 13:24:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// C++11 [expr.shift]p1: Shift width must be less than the bit width of
|
|
|
|
// the shifted type.
|
|
|
|
if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
const APSInt Val = RHS.toAPSInt();
|
|
|
|
QualType Ty = E->getType();
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
|
2024-07-24 12:36:08 -07:00
|
|
|
if (!S.noteUndefinedBehavior())
|
|
|
|
return false;
|
2023-01-19 13:24:40 +01:00
|
|
|
}
|
2023-05-09 19:38:37 +02:00
|
|
|
|
|
|
|
if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
// C++11 [expr.shift]p2: A signed left shift must have a non-negative
|
|
|
|
// operand, and must not overflow the corresponding unsigned type.
|
2024-07-24 12:36:08 -07:00
|
|
|
if (LHS.isNegative()) {
|
2023-05-09 19:38:37 +02:00
|
|
|
S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
|
2024-07-24 12:36:08 -07:00
|
|
|
if (!S.noteUndefinedBehavior())
|
|
|
|
return false;
|
|
|
|
} else if (LHS.toUnsigned().countLeadingZeros() <
|
|
|
|
static_cast<unsigned>(RHS)) {
|
2023-05-09 19:38:37 +02:00
|
|
|
S.CCEDiag(E, diag::note_constexpr_lshift_discards);
|
2024-07-24 12:36:08 -07:00
|
|
|
if (!S.noteUndefinedBehavior())
|
|
|
|
return false;
|
|
|
|
}
|
2023-05-09 19:38:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// C++2a [expr.shift]p2: [P0907R4]:
|
|
|
|
// E1 << E2 is the unique value congruent to
|
|
|
|
// E1 x 2^E2 module 2^N.
|
2023-01-19 13:24:40 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-07 10:38:33 +02:00
|
|
|
/// Checks if Div/Rem operation on LHS and RHS is valid.
|
|
|
|
template <typename T>
|
2023-01-19 12:37:20 +01:00
|
|
|
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
|
|
|
|
if (RHS.isZero()) {
|
2023-08-09 14:27:46 +02:00
|
|
|
const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
|
2024-07-22 11:59:02 +02:00
|
|
|
if constexpr (std::is_same_v<T, Floating>) {
|
|
|
|
S.CCEDiag(Op, diag::note_expr_divide_by_zero)
|
|
|
|
<< Op->getRHS()->getSourceRange();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-08-09 14:27:46 +02:00
|
|
|
S.FFDiag(Op, diag::note_expr_divide_by_zero)
|
|
|
|
<< Op->getRHS()->getSourceRange();
|
2024-07-22 11:59:02 +02:00
|
|
|
return false;
|
2023-01-19 12:37:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
|
|
|
|
APSInt LHSInt = LHS.toAPSInt();
|
|
|
|
SmallString<32> Trunc;
|
|
|
|
(-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2022-10-07 10:38:33 +02:00
|
|
|
|
2024-07-15 13:19:33 +02:00
|
|
|
template <typename SizeT>
|
|
|
|
bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
|
|
|
|
unsigned ElemSize, bool IsNoThrow) {
|
|
|
|
// FIXME: Both the SizeT::from() as well as the
|
|
|
|
// NumElements.toAPSInt() in this function are rather expensive.
|
|
|
|
|
|
|
|
// FIXME: GH63562
|
|
|
|
// APValue stores array extents as unsigned,
|
|
|
|
// so anything that is greater that unsigned would overflow when
|
|
|
|
// constructing the array, we catch this here.
|
|
|
|
SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
|
|
|
|
if (NumElements->toAPSInt().getActiveBits() >
|
|
|
|
ConstantArrayType::getMaxSizeBits(S.getCtx()) ||
|
|
|
|
*NumElements > MaxElements) {
|
|
|
|
if (!IsNoThrow) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_new_too_large)
|
|
|
|
<< NumElements->toDiagnosticString(S.getCtx());
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-09-05 09:47:05 +02:00
|
|
|
/// Checks if the result of a floating-point operation is valid
|
2023-01-25 14:51:16 +01:00
|
|
|
/// in the current context.
|
2023-07-28 08:07:51 +02:00
|
|
|
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
|
|
|
|
APFloat::opStatus Status);
|
2023-01-25 14:51:16 +01:00
|
|
|
|
2023-07-28 08:37:41 +02:00
|
|
|
/// Checks why the given DeclRefExpr is invalid.
|
|
|
|
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
|
|
|
|
|
2022-10-07 15:49:37 +02:00
|
|
|
/// Interpreter entry point.
|
|
|
|
bool Interpret(InterpState &S, APValue &Result);
|
|
|
|
|
2023-01-07 12:05:05 +01:00
|
|
|
/// Interpret a builtin function.
|
2023-07-18 07:47:20 +02:00
|
|
|
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
|
|
|
|
const CallExpr *Call);
|
2022-11-05 13:08:40 +01:00
|
|
|
|
2023-07-27 08:30:59 +02:00
|
|
|
/// Interpret an offsetof operation.
|
|
|
|
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
|
|
|
|
llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
|
|
|
|
|
2024-03-01 11:35:33 +01:00
|
|
|
inline bool Invalid(InterpState &S, CodePtr OpPC);
|
|
|
|
|
2022-11-02 09:09:23 +01:00
|
|
|
enum class ArithOp { Add, Sub };
|
|
|
|
|
2023-01-07 12:05:05 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Returning values
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2023-10-24 12:33:29 +02:00
|
|
|
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
|
2023-07-28 21:01:05 +02:00
|
|
|
|
2023-05-11 12:01:17 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
2023-01-07 12:05:05 +01:00
|
|
|
bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
|
|
|
|
const T &Ret = S.Stk.pop<T>();
|
|
|
|
|
2023-07-09 20:09:59 +02:00
|
|
|
// Make sure returned pointers are live. We might be trying to return a
|
|
|
|
// pointer or reference to a local variable.
|
|
|
|
// Just return false, since a diagnostic has already been emitted in Sema.
|
|
|
|
if constexpr (std::is_same_v<T, Pointer>) {
|
|
|
|
// FIXME: We could be calling isLive() here, but the emitted diagnostics
|
|
|
|
// seem a little weird, at least if the returned expression is of
|
|
|
|
// pointer type.
|
2023-10-10 11:19:14 +02:00
|
|
|
// Null pointers are considered live here.
|
|
|
|
if (!Ret.isZero() && !Ret.isLive())
|
2023-07-09 20:09:59 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-08-24 11:36:23 -07:00
|
|
|
assert(S.Current);
|
2023-01-07 12:05:05 +01:00
|
|
|
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
|
2023-10-24 12:33:29 +02:00
|
|
|
if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
|
|
|
|
cleanupAfterFunctionCall(S, PC);
|
2023-01-07 12:05:05 +01:00
|
|
|
|
|
|
|
if (InterpFrame *Caller = S.Current->Caller) {
|
|
|
|
PC = S.Current->getRetPC();
|
|
|
|
delete S.Current;
|
|
|
|
S.Current = Caller;
|
|
|
|
S.Stk.push<T>(Ret);
|
|
|
|
} else {
|
|
|
|
delete S.Current;
|
|
|
|
S.Current = nullptr;
|
2024-07-20 15:25:00 +02:00
|
|
|
if (!ReturnValue<T>(S, Ret, Result))
|
2023-01-07 12:05:05 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
|
|
|
|
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
|
2023-10-24 12:33:29 +02:00
|
|
|
|
2023-05-11 12:01:17 +02:00
|
|
|
if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
|
2023-10-24 12:33:29 +02:00
|
|
|
cleanupAfterFunctionCall(S, PC);
|
2023-01-07 12:05:05 +01:00
|
|
|
|
|
|
|
if (InterpFrame *Caller = S.Current->Caller) {
|
|
|
|
PC = S.Current->getRetPC();
|
|
|
|
delete S.Current;
|
|
|
|
S.Current = Caller;
|
|
|
|
} else {
|
|
|
|
delete S.Current;
|
|
|
|
S.Current = nullptr;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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, Sub, Mul
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <typename T, bool (*OpFW)(T, T, unsigned, T *),
|
|
|
|
template <typename U> class OpAP>
|
|
|
|
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
|
|
|
|
const T &RHS) {
|
|
|
|
// Fast path - add the numbers with fixed width.
|
|
|
|
T Result;
|
|
|
|
if (!OpFW(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If for some reason evaluation continues, use the truncated results.
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
|
|
|
|
// Slow path - compute the result using another bit of precision.
|
|
|
|
APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
|
|
|
|
|
|
|
|
// Report undefined behaviour, stopping if required.
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
if (S.checkingForUndefinedBehavior()) {
|
2021-06-09 11:06:23 +01:00
|
|
|
SmallString<32> Trunc;
|
2024-03-05 04:38:42 -08:00
|
|
|
Value.trunc(Result.bitWidth())
|
|
|
|
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
|
|
|
|
/*UpperCase=*/true, /*InsertSeparators=*/true);
|
[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
|
|
|
auto Loc = E->getExprLoc();
|
2023-08-19 22:05:12 +09:00
|
|
|
S.report(Loc, diag::warn_integer_constant_overflow)
|
|
|
|
<< Trunc << Type << E->getSourceRange();
|
[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
|
|
|
}
|
2024-07-13 16:28:00 +02:00
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
|
|
|
|
|
|
|
|
if (!S.noteUndefinedBehavior()) {
|
|
|
|
S.Stk.pop<T>();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
[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
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Add(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
const unsigned Bits = RHS.bitWidth() + 1;
|
|
|
|
return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Floating &RHS = S.Stk.pop<Floating>();
|
|
|
|
const Floating &LHS = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
Floating Result;
|
|
|
|
auto Status = Floating::add(LHS, RHS, RM, &Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
2023-07-28 08:07:51 +02:00
|
|
|
return CheckFloatResult(S, OpPC, Result, Status);
|
2023-01-25 14:51:16 +01:00
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Sub(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
const unsigned Bits = RHS.bitWidth() + 1;
|
|
|
|
return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Floating &RHS = S.Stk.pop<Floating>();
|
|
|
|
const Floating &LHS = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
Floating Result;
|
|
|
|
auto Status = Floating::sub(LHS, RHS, RM, &Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
2023-07-28 08:07:51 +02:00
|
|
|
return CheckFloatResult(S, OpPC, Result, Status);
|
2023-01-25 14:51:16 +01:00
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Mul(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
const unsigned Bits = RHS.bitWidth() * 2;
|
|
|
|
return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Floating &RHS = S.Stk.pop<Floating>();
|
|
|
|
const Floating &LHS = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
Floating Result;
|
|
|
|
auto Status = Floating::mul(LHS, RHS, RM, &Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
2023-07-28 08:07:51 +02:00
|
|
|
return CheckFloatResult(S, OpPC, Result, Status);
|
2023-01-25 14:51:16 +01:00
|
|
|
}
|
2024-06-17 16:07:58 +02:00
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool Mulc(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &RHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &LHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &Result = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
if constexpr (std::is_same_v<T, Floating>) {
|
|
|
|
APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
|
|
|
|
APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
|
|
|
|
APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
|
|
|
|
APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
|
|
|
|
|
|
|
|
APFloat ResR(A.getSemantics());
|
|
|
|
APFloat ResI(A.getSemantics());
|
|
|
|
HandleComplexComplexMul(A, B, C, D, ResR, ResI);
|
|
|
|
|
|
|
|
// Copy into the result.
|
|
|
|
Result.atIndex(0).deref<Floating>() = Floating(ResR);
|
|
|
|
Result.atIndex(0).initialize();
|
|
|
|
Result.atIndex(1).deref<Floating>() = Floating(ResI);
|
|
|
|
Result.atIndex(1).initialize();
|
|
|
|
Result.initialize();
|
|
|
|
} else {
|
|
|
|
// Integer element type.
|
|
|
|
const T &LHSR = LHS.atIndex(0).deref<T>();
|
|
|
|
const T &LHSI = LHS.atIndex(1).deref<T>();
|
|
|
|
const T &RHSR = RHS.atIndex(0).deref<T>();
|
|
|
|
const T &RHSI = RHS.atIndex(1).deref<T>();
|
|
|
|
unsigned Bits = LHSR.bitWidth();
|
|
|
|
|
|
|
|
// real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
|
|
|
|
T A;
|
|
|
|
if (T::mul(LHSR, RHSR, Bits, &A))
|
|
|
|
return false;
|
|
|
|
T B;
|
|
|
|
if (T::mul(LHSI, RHSI, Bits, &B))
|
|
|
|
return false;
|
|
|
|
if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))
|
|
|
|
return false;
|
|
|
|
Result.atIndex(0).initialize();
|
|
|
|
|
|
|
|
// imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
|
|
|
|
if (T::mul(LHSR, RHSI, Bits, &A))
|
|
|
|
return false;
|
|
|
|
if (T::mul(LHSI, RHSR, Bits, &B))
|
|
|
|
return false;
|
|
|
|
if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))
|
|
|
|
return false;
|
|
|
|
Result.atIndex(1).initialize();
|
|
|
|
Result.initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-06-18 13:49:02 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool Divc(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &RHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &LHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &Result = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
if constexpr (std::is_same_v<T, Floating>) {
|
|
|
|
APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
|
|
|
|
APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
|
|
|
|
APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
|
|
|
|
APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
|
|
|
|
|
|
|
|
APFloat ResR(A.getSemantics());
|
|
|
|
APFloat ResI(A.getSemantics());
|
|
|
|
HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
|
|
|
|
|
|
|
|
// Copy into the result.
|
|
|
|
Result.atIndex(0).deref<Floating>() = Floating(ResR);
|
|
|
|
Result.atIndex(0).initialize();
|
|
|
|
Result.atIndex(1).deref<Floating>() = Floating(ResI);
|
|
|
|
Result.atIndex(1).initialize();
|
|
|
|
Result.initialize();
|
|
|
|
} else {
|
|
|
|
// Integer element type.
|
|
|
|
const T &LHSR = LHS.atIndex(0).deref<T>();
|
|
|
|
const T &LHSI = LHS.atIndex(1).deref<T>();
|
|
|
|
const T &RHSR = RHS.atIndex(0).deref<T>();
|
|
|
|
const T &RHSI = RHS.atIndex(1).deref<T>();
|
|
|
|
unsigned Bits = LHSR.bitWidth();
|
|
|
|
const T Zero = T::from(0, Bits);
|
|
|
|
|
|
|
|
if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&
|
|
|
|
Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {
|
|
|
|
const SourceInfo &E = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(E, diag::note_expr_divide_by_zero);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Den = real(RHS)² + imag(RHS)²
|
|
|
|
T A, B;
|
|
|
|
if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B))
|
|
|
|
return false;
|
|
|
|
T Den;
|
|
|
|
if (T::add(A, B, Bits, &Den))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
|
|
|
|
T &ResultR = Result.atIndex(0).deref<T>();
|
|
|
|
T &ResultI = Result.atIndex(1).deref<T>();
|
|
|
|
|
|
|
|
if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
|
|
|
|
return false;
|
|
|
|
if (T::add(A, B, Bits, &ResultR))
|
|
|
|
return false;
|
|
|
|
if (T::div(ResultR, Den, Bits, &ResultR))
|
|
|
|
return false;
|
|
|
|
Result.atIndex(0).initialize();
|
|
|
|
|
|
|
|
// imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
|
|
|
|
if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
|
|
|
|
return false;
|
|
|
|
if (T::sub(A, B, Bits, &ResultI))
|
|
|
|
return false;
|
|
|
|
if (T::div(ResultI, Den, Bits, &ResultI))
|
|
|
|
return false;
|
|
|
|
Result.atIndex(1).initialize();
|
|
|
|
Result.initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-09-30 16:59:50 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS & RHS' on the stack
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool BitAnd(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
unsigned Bits = RHS.bitWidth();
|
|
|
|
T Result;
|
|
|
|
if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-06 15:13:11 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS | RHS' on the stack
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool BitOr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
unsigned Bits = RHS.bitWidth();
|
|
|
|
T Result;
|
|
|
|
if (!T::bitOr(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-22 16:59:19 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS ^ RHS' on the stack
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool BitXor(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
unsigned Bits = RHS.bitWidth();
|
|
|
|
T Result;
|
|
|
|
if (!T::bitXor(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:40:55 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Rem(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
2022-10-07 10:38:33 +02:00
|
|
|
if (!CheckDivRem(S, OpPC, LHS, RHS))
|
2022-09-27 17:40:55 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
const unsigned Bits = RHS.bitWidth() * 2;
|
|
|
|
T Result;
|
|
|
|
if (!T::rem(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-27 18:17:52 +02:00
|
|
|
/// 1) Pops the RHS from the stack.
|
|
|
|
/// 2) Pops the LHS from the stack.
|
|
|
|
/// 3) Pushes 'LHS / RHS' on the stack
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Div(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
|
2022-10-07 10:38:33 +02:00
|
|
|
if (!CheckDivRem(S, OpPC, LHS, RHS))
|
2022-09-27 18:17:52 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
const unsigned Bits = RHS.bitWidth() * 2;
|
|
|
|
T Result;
|
|
|
|
if (!T::div(LHS, RHS, Bits, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Floating &RHS = S.Stk.pop<Floating>();
|
|
|
|
const Floating &LHS = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
if (!CheckDivRem(S, OpPC, LHS, RHS))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Floating Result;
|
|
|
|
auto Status = Floating::div(LHS, RHS, RM, &Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
2023-07-28 08:07:51 +02:00
|
|
|
return CheckFloatResult(S, OpPC, Result, Status);
|
2023-01-25 14:51:16 +01:00
|
|
|
}
|
|
|
|
|
[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
|
|
|
//===----------------------------------------------------------------------===//
|
2022-08-09 08:08:48 +02:00
|
|
|
// Inv
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2024-08-18 15:59:59 +02:00
|
|
|
inline bool Inv(InterpState &S, CodePtr OpPC) {
|
|
|
|
const auto &Val = S.Stk.pop<Boolean>();
|
|
|
|
S.Stk.push<Boolean>(!Val);
|
2022-08-09 08:08:48 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Neg
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Neg(InterpState &S, CodePtr OpPC) {
|
2023-04-22 14:09:14 +02:00
|
|
|
const T &Value = S.Stk.pop<T>();
|
2022-08-09 08:08:48 +02:00
|
|
|
T Result;
|
|
|
|
|
2023-04-22 14:09:14 +02:00
|
|
|
if (!T::neg(Value, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(isIntegralType(Name) &&
|
|
|
|
"don't expect other types to fail at constexpr negation");
|
2022-08-09 08:08:48 +02:00
|
|
|
S.Stk.push<T>(Result);
|
2023-04-22 14:09:14 +02:00
|
|
|
|
|
|
|
APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
|
|
|
|
if (S.checkingForUndefinedBehavior()) {
|
|
|
|
SmallString<32> Trunc;
|
2024-03-05 04:38:42 -08:00
|
|
|
NegatedValue.trunc(Result.bitWidth())
|
|
|
|
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
|
|
|
|
/*UpperCase=*/true, /*InsertSeparators=*/true);
|
2023-04-22 14:09:14 +02:00
|
|
|
auto Loc = E->getExprLoc();
|
2023-08-19 22:05:12 +09:00
|
|
|
S.report(Loc, diag::warn_integer_constant_overflow)
|
|
|
|
<< Trunc << Type << E->getSourceRange();
|
2023-04-22 14:09:14 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
|
|
|
|
return S.noteUndefinedBehavior();
|
2022-08-09 08:08:48 +02:00
|
|
|
}
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
enum class PushVal : bool {
|
|
|
|
No,
|
|
|
|
Yes,
|
|
|
|
};
|
|
|
|
enum class IncDecOp {
|
|
|
|
Inc,
|
|
|
|
Dec,
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T, IncDecOp Op, PushVal DoPush>
|
|
|
|
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
|
2024-03-06 16:56:11 +01:00
|
|
|
assert(!Ptr.isDummy());
|
2024-01-31 14:36:23 +01:00
|
|
|
|
2024-03-01 11:35:33 +01:00
|
|
|
if constexpr (std::is_same_v<T, Boolean>) {
|
|
|
|
if (!S.getLangOpts().CPlusPlus14)
|
|
|
|
return Invalid(S, OpPC);
|
|
|
|
}
|
|
|
|
|
2023-10-19 14:20:16 +02:00
|
|
|
const T &Value = Ptr.deref<T>();
|
2022-10-21 09:10:29 +02:00
|
|
|
T Result;
|
|
|
|
|
|
|
|
if constexpr (DoPush == PushVal::Yes)
|
2023-04-21 09:52:43 +02:00
|
|
|
S.Stk.push<T>(Value);
|
2022-10-21 09:10:29 +02:00
|
|
|
|
|
|
|
if constexpr (Op == IncDecOp::Inc) {
|
|
|
|
if (!T::increment(Value, &Result)) {
|
|
|
|
Ptr.deref<T>() = Result;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!T::decrement(Value, &Result)) {
|
|
|
|
Ptr.deref<T>() = Result;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Something went wrong with the previous operation. Compute the
|
|
|
|
// result with another bit of precision.
|
|
|
|
unsigned Bits = Value.bitWidth() + 1;
|
|
|
|
APSInt APResult;
|
|
|
|
if constexpr (Op == IncDecOp::Inc)
|
|
|
|
APResult = ++Value.toAPSInt(Bits);
|
|
|
|
else
|
|
|
|
APResult = --Value.toAPSInt(Bits);
|
|
|
|
|
|
|
|
// Report undefined behaviour, stopping if required.
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
if (S.checkingForUndefinedBehavior()) {
|
|
|
|
SmallString<32> Trunc;
|
2024-03-05 04:38:42 -08:00
|
|
|
APResult.trunc(Result.bitWidth())
|
|
|
|
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
|
|
|
|
/*UpperCase=*/true, /*InsertSeparators=*/true);
|
2022-10-21 09:10:29 +02:00
|
|
|
auto Loc = E->getExprLoc();
|
2023-08-19 22:05:12 +09:00
|
|
|
S.report(Loc, diag::warn_integer_constant_overflow)
|
|
|
|
<< Trunc << Type << E->getSourceRange();
|
2022-10-21 09:10:29 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
|
|
|
|
return S.noteUndefinedBehavior();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Load the value from the pointer
|
|
|
|
/// 3) Writes the value increased by one back to the pointer
|
|
|
|
/// 4) Pushes the original (pre-inc) value on the stack.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Inc(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-06-29 06:57:26 +02:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
|
2023-05-04 15:31:24 +02:00
|
|
|
return false;
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Load the value from the pointer
|
|
|
|
/// 3) Writes the value increased by one back to the pointer
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool IncPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-06-29 06:57:26 +02:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
|
2023-05-04 15:31:24 +02:00
|
|
|
return false;
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Load the value from the pointer
|
|
|
|
/// 3) Writes the value decreased by one back to the pointer
|
|
|
|
/// 4) Pushes the original (pre-dec) value on the stack.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Dec(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-06-29 06:57:26 +02:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
|
2023-05-04 15:31:24 +02:00
|
|
|
return false;
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Load the value from the pointer
|
|
|
|
/// 3) Writes the value decreased by one back to the pointer
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool DecPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-06-29 06:57:26 +02:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
|
2023-05-04 15:31:24 +02:00
|
|
|
return false;
|
|
|
|
|
2022-10-21 09:10:29 +02:00
|
|
|
return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
|
|
|
|
}
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
template <IncDecOp Op, PushVal DoPush>
|
|
|
|
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
|
|
|
|
llvm::RoundingMode RM) {
|
|
|
|
Floating Value = Ptr.deref<Floating>();
|
|
|
|
Floating Result;
|
|
|
|
|
|
|
|
if constexpr (DoPush == PushVal::Yes)
|
|
|
|
S.Stk.push<Floating>(Value);
|
|
|
|
|
|
|
|
llvm::APFloat::opStatus Status;
|
|
|
|
if constexpr (Op == IncDecOp::Inc)
|
|
|
|
Status = Floating::increment(Value, RM, &Result);
|
|
|
|
else
|
|
|
|
Status = Floating::decrement(Value, RM, &Result);
|
|
|
|
|
|
|
|
Ptr.deref<Floating>() = Result;
|
|
|
|
|
2023-07-28 08:07:51 +02:00
|
|
|
return CheckFloatResult(S, OpPC, Result, Status);
|
2023-04-21 10:41:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-06-29 06:57:26 +02:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
|
2023-05-04 15:31:24 +02:00
|
|
|
return false;
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-06-29 06:57:26 +02:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
|
2023-05-04 15:31:24 +02:00
|
|
|
return false;
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-06-29 06:57:26 +02:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
|
2023-05-04 15:31:24 +02:00
|
|
|
return false;
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-06-29 06:57:26 +02:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
|
2023-05-04 15:31:24 +02:00
|
|
|
return false;
|
|
|
|
|
2023-04-21 10:41:40 +02:00
|
|
|
return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
|
|
|
|
}
|
|
|
|
|
2022-09-28 14:30:44 +02:00
|
|
|
/// 1) Pops the value from the stack.
|
|
|
|
/// 2) Pushes the bitwise complemented value on the stack (~V).
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Comp(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Val = S.Stk.pop<T>();
|
|
|
|
T Result;
|
|
|
|
if (!T::comp(Val, &Result)) {
|
|
|
|
S.Stk.push<T>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-09 08:08:48 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
[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
|
|
|
// EQ, NE, GT, GE, LT, LE
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
|
2024-06-06 11:17:48 +02:00
|
|
|
assert((!std::is_same_v<T, MemberPointer>) &&
|
|
|
|
"Non-equality comparisons on member pointer types should already be "
|
|
|
|
"rejected in Sema.");
|
[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 BoolT = PrimConv<PT_Bool>::T;
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
|
|
|
|
return CmpHelper<T>(S, OpPC, Fn);
|
|
|
|
}
|
|
|
|
|
2023-04-25 15:46:20 +02:00
|
|
|
/// Function pointers cannot be compared in an ordered way.
|
|
|
|
template <>
|
|
|
|
inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
|
|
|
|
CompareFn Fn) {
|
|
|
|
const auto &RHS = S.Stk.pop<FunctionPointer>();
|
|
|
|
const auto &LHS = S.Stk.pop<FunctionPointer>();
|
|
|
|
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
|
|
|
|
<< LHS.toDiagnosticString(S.getCtx())
|
|
|
|
<< RHS.toDiagnosticString(S.getCtx());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
|
|
|
|
CompareFn Fn) {
|
|
|
|
const auto &RHS = S.Stk.pop<FunctionPointer>();
|
|
|
|
const auto &LHS = S.Stk.pop<FunctionPointer>();
|
2024-03-04 17:15:09 +01:00
|
|
|
|
|
|
|
// We cannot compare against weak declarations at compile time.
|
|
|
|
for (const auto &FP : {LHS, RHS}) {
|
2024-04-12 08:52:18 +02:00
|
|
|
if (FP.isWeak()) {
|
2024-03-04 17:15:09 +01:00
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
|
|
|
|
<< FP.toDiagnosticString(S.getCtx());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-25 15:46:20 +02:00
|
|
|
S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <>
|
|
|
|
inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
|
|
|
|
using BoolT = PrimConv<PT_Bool>::T;
|
|
|
|
const Pointer &RHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &LHS = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
if (!Pointer::hasSameBase(LHS, RHS)) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
2023-04-25 19:53:40 +02:00
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
|
|
|
|
<< LHS.toDiagnosticString(S.getCtx())
|
|
|
|
<< RHS.toDiagnosticString(S.getCtx());
|
[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
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
unsigned VL = LHS.getByteOffset();
|
|
|
|
unsigned VR = RHS.getByteOffset();
|
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
|
|
|
|
using BoolT = PrimConv<PT_Bool>::T;
|
|
|
|
const Pointer &RHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &LHS = S.Stk.pop<Pointer>();
|
|
|
|
|
2019-12-16 17:40:03 -08:00
|
|
|
if (LHS.isZero() && RHS.isZero()) {
|
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-07-03 11:29:07 +02:00
|
|
|
// Reject comparisons to weak pointers.
|
2024-04-09 10:24:03 +02:00
|
|
|
for (const auto &P : {LHS, RHS}) {
|
|
|
|
if (P.isZero())
|
|
|
|
continue;
|
2024-04-10 12:53:54 +02:00
|
|
|
if (P.isWeak()) {
|
2024-04-09 10:24:03 +02:00
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
|
|
|
|
<< P.toDiagnosticString(S.getCtx());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[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 (!Pointer::hasSameBase(LHS, RHS)) {
|
2024-07-03 11:29:07 +02:00
|
|
|
if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
|
|
|
|
RHS.getOffset() == 0) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
|
|
|
|
<< LHS.toDiagnosticString(S.getCtx());
|
|
|
|
return false;
|
|
|
|
} else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
|
|
|
|
LHS.getOffset() == 0) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
|
|
|
|
<< RHS.toDiagnosticString(S.getCtx());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
unsigned VL = LHS.getByteOffset();
|
|
|
|
unsigned VR = RHS.getByteOffset();
|
2022-10-13 10:09:36 +02:00
|
|
|
|
|
|
|
// In our Pointer class, a pointer to an array and a pointer to the first
|
|
|
|
// element in the same array are NOT equal. They have the same Base value,
|
|
|
|
// but a different Offset. This is a pretty rare case, so we fix this here
|
|
|
|
// by comparing pointers to the first elements.
|
2024-05-11 06:13:15 +02:00
|
|
|
if (!LHS.isZero() && LHS.isArrayRoot())
|
2022-10-13 10:09:36 +02:00
|
|
|
VL = LHS.atIndex(0).getByteOffset();
|
2024-05-11 06:13:15 +02:00
|
|
|
if (!RHS.isZero() && RHS.isArrayRoot())
|
2022-10-13 10:09:36 +02:00
|
|
|
VR = RHS.atIndex(0).getByteOffset();
|
|
|
|
|
[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
|
|
|
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-06 11:17:48 +02:00
|
|
|
template <>
|
|
|
|
inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
|
|
|
|
CompareFn Fn) {
|
|
|
|
const auto &RHS = S.Stk.pop<MemberPointer>();
|
|
|
|
const auto &LHS = S.Stk.pop<MemberPointer>();
|
|
|
|
|
|
|
|
// If either operand is a pointer to a weak function, the comparison is not
|
|
|
|
// constant.
|
|
|
|
for (const auto &MP : {LHS, RHS}) {
|
|
|
|
if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++11 [expr.eq]p2:
|
|
|
|
// If both operands are null, they compare equal. Otherwise if only one is
|
|
|
|
// null, they compare unequal.
|
|
|
|
if (LHS.isZero() && RHS.isZero()) {
|
|
|
|
S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (LHS.isZero() || RHS.isZero()) {
|
|
|
|
S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We cannot compare against virtual declarations at compile time.
|
|
|
|
for (const auto &MP : {LHS, RHS}) {
|
|
|
|
if (const CXXMethodDecl *MD = MP.getMemberFunction();
|
|
|
|
MD && MD->isVirtual()) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool EQ(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Equal;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-29 09:41:58 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
|
|
|
|
const T &RHS = S.Stk.pop<T>();
|
|
|
|
const T &LHS = S.Stk.pop<T>();
|
|
|
|
const Pointer &P = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
ComparisonCategoryResult CmpResult = LHS.compare(RHS);
|
|
|
|
if (CmpResult == ComparisonCategoryResult::Unordered) {
|
|
|
|
// This should only happen with pointers.
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
|
|
|
|
<< LHS.toDiagnosticString(S.getCtx())
|
|
|
|
<< RHS.toDiagnosticString(S.getCtx());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(CmpInfo);
|
2024-02-26 09:07:53 +01:00
|
|
|
const auto *CmpValueInfo =
|
|
|
|
CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
|
2023-09-29 09:41:58 +02:00
|
|
|
assert(CmpValueInfo);
|
|
|
|
assert(CmpValueInfo->hasValidIntValue());
|
2024-03-13 15:55:18 +00:00
|
|
|
return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
|
2023-09-29 09:41:58 +02:00
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool NE(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R != ComparisonCategoryResult::Equal;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool LT(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Less;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool LE(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Less ||
|
|
|
|
R == ComparisonCategoryResult::Equal;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GT(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Greater;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GE(InterpState &S, CodePtr OpPC) {
|
|
|
|
return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
|
|
|
|
return R == ComparisonCategoryResult::Greater ||
|
|
|
|
R == ComparisonCategoryResult::Equal;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// InRange
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InRange(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T RHS = S.Stk.pop<T>();
|
|
|
|
const T LHS = S.Stk.pop<T>();
|
|
|
|
const T Value = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
S.Stk.push<bool>(LHS <= Value && Value <= RHS);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Dup, Pop, Test
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Dup(InterpState &S, CodePtr OpPC) {
|
|
|
|
S.Stk.push<T>(S.Stk.peek<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Pop(InterpState &S, CodePtr OpPC) {
|
|
|
|
S.Stk.pop<T>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-08-03 12:25:20 +02:00
|
|
|
/// [Value1, Value2] -> [Value2, Value1]
|
|
|
|
template <PrimType TopName, PrimType BottomName>
|
|
|
|
bool Flip(InterpState &S, CodePtr OpPC) {
|
|
|
|
using TopT = typename PrimConv<TopName>::T;
|
|
|
|
using BottomT = typename PrimConv<BottomName>::T;
|
|
|
|
|
|
|
|
const auto &Top = S.Stk.pop<TopT>();
|
|
|
|
const auto &Bottom = S.Stk.pop<BottomT>();
|
|
|
|
|
|
|
|
S.Stk.push<TopT>(Top);
|
|
|
|
S.Stk.push<BottomT>(Bottom);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
|
|
|
|
S.Stk.push<T>(Arg);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Get/Set Local/Param/Global/This
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
2022-12-26 09:29:04 +01:00
|
|
|
const Pointer &Ptr = S.Current->getLocalPointer(I);
|
|
|
|
if (!CheckLoad(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Ptr.deref<T>());
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-04-30 16:02:46 +02:00
|
|
|
/// 1) Pops the value from the stack.
|
|
|
|
/// 2) Writes the value to the local variable with the
|
|
|
|
/// given offset.
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Current->setLocal<T>(I, S.Stk.pop<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
S.Stk.push<T>(S.Current->getParam<T>(I));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Current->setParam<T>(I, S.Stk.pop<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-15 09:22:34 +02:00
|
|
|
/// 1) Peeks a pointer on the stack
|
|
|
|
/// 2) Pushes the value of the pointer's field on the stack
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const Pointer &Obj = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Obj, CSK_Field))
|
2024-08-16 17:13:12 +02:00
|
|
|
return false;
|
[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 (!CheckRange(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = Obj.atField(I);
|
|
|
|
if (!CheckLoad(S, OpPC, Field))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Field.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Obj = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = Obj.atField(I);
|
|
|
|
if (!CheckStore(S, OpPC, Field))
|
|
|
|
return false;
|
2023-03-14 11:08:16 +01:00
|
|
|
Field.initialize();
|
[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
|
|
|
Field.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-15 09:22:34 +02:00
|
|
|
/// 1) Pops a pointer from the stack
|
|
|
|
/// 2) Pushes the value of the pointer's field on the stack
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const Pointer &Obj = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Obj, CSK_Field))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = Obj.atField(I);
|
|
|
|
if (!CheckLoad(S, OpPC, Field))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Field.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = This.atField(I);
|
|
|
|
if (!CheckLoad(S, OpPC, Field))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<T>(Field.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = This.atField(I);
|
|
|
|
if (!CheckStore(S, OpPC, Field))
|
|
|
|
return false;
|
|
|
|
Field.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
2024-01-31 08:03:37 +01:00
|
|
|
const Pointer &Ptr = S.P.getPtrGlobal(I);
|
|
|
|
if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
|
2024-01-13 05:51:03 +01:00
|
|
|
return false;
|
2024-01-31 08:03:37 +01:00
|
|
|
if (Ptr.isExtern())
|
[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
|
|
|
return false;
|
2024-01-31 08:03:37 +01:00
|
|
|
|
|
|
|
// If a global variable is uninitialized, that means the initializer we've
|
|
|
|
// compiled for it wasn't a constant expression. Diagnose that.
|
|
|
|
if (!CheckGlobalInitialized(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
S.Stk.push<T>(Ptr.deref<T>());
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-01-13 05:51:03 +01:00
|
|
|
/// Same as GetGlobal, but without the checks.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
|
2024-06-28 12:48:57 +02:00
|
|
|
const Pointer &Ptr = S.P.getPtrGlobal(I);
|
|
|
|
if (!Ptr.isInitialized())
|
|
|
|
return false;
|
2024-07-16 19:00:45 +02:00
|
|
|
S.Stk.push<T>(Ptr.deref<T>());
|
2024-01-13 05:51:03 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
// TODO: emit warning.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
2024-01-31 08:03:37 +01:00
|
|
|
const Pointer &P = S.P.getGlobal(I);
|
|
|
|
P.deref<T>() = S.Stk.pop<T>();
|
|
|
|
P.initialize();
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-15 14:40:23 +02:00
|
|
|
/// 1) Converts the value on top of the stack to an APValue
|
|
|
|
/// 2) Sets that APValue on \Temp
|
2024-02-26 13:56:10 +01:00
|
|
|
/// 3) Initializes global with index \I with that
|
2022-10-15 14:40:23 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
|
|
|
|
const LifetimeExtendedTemporaryDecl *Temp) {
|
2024-06-28 13:23:51 +02:00
|
|
|
const Pointer &Ptr = S.P.getGlobal(I);
|
|
|
|
|
2022-10-15 14:40:23 +02:00
|
|
|
const T Value = S.Stk.peek<T>();
|
2024-07-20 15:25:00 +02:00
|
|
|
APValue APV = Value.toAPValue(S.getCtx());
|
2022-10-15 14:40:23 +02:00
|
|
|
APValue *Cached = Temp->getOrCreateValue(true);
|
|
|
|
*Cached = APV;
|
|
|
|
|
2024-06-28 13:23:51 +02:00
|
|
|
assert(Ptr.getDeclDesc()->asExpr());
|
|
|
|
|
|
|
|
S.SeenGlobalTemporaries.push_back(
|
|
|
|
std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
|
2024-01-31 08:03:37 +01:00
|
|
|
|
2024-06-28 13:23:51 +02:00
|
|
|
Ptr.deref<T>() = S.Stk.pop<T>();
|
|
|
|
Ptr.initialize();
|
2022-10-15 14:40:23 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-02-21 09:36:37 +01:00
|
|
|
/// 1) Converts the value on top of the stack to an APValue
|
|
|
|
/// 2) Sets that APValue on \Temp
|
|
|
|
/// 3) Initialized global with index \I with that
|
|
|
|
inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
|
|
|
|
const LifetimeExtendedTemporaryDecl *Temp) {
|
|
|
|
assert(Temp);
|
|
|
|
const Pointer &P = S.Stk.peek<Pointer>();
|
|
|
|
APValue *Cached = Temp->getOrCreateValue(true);
|
|
|
|
|
2024-06-28 13:23:51 +02:00
|
|
|
S.SeenGlobalTemporaries.push_back(
|
|
|
|
std::make_pair(P.getDeclDesc()->asExpr(), Temp));
|
|
|
|
|
2024-07-05 07:52:15 +02:00
|
|
|
if (std::optional<APValue> APV =
|
|
|
|
P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
|
2024-01-19 10:08:03 +01:00
|
|
|
*Cached = *APV;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2023-02-21 09:36:37 +01:00
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
const Pointer &Field = This.atField(I);
|
|
|
|
Field.deref<T>() = S.Stk.pop<T>();
|
2024-08-10 16:32:15 +02:00
|
|
|
Field.activate();
|
[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
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-01-18 16:25:05 +01:00
|
|
|
// FIXME: The Field pointer here is too much IMO and we could instead just
|
|
|
|
// pass an Offset + BitWidth pair.
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
2024-01-18 16:25:05 +01:00
|
|
|
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
|
|
|
|
uint32_t FieldOffset) {
|
2023-08-10 09:19:05 +02:00
|
|
|
assert(F->isBitField());
|
[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 (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
2024-01-18 16:25:05 +01:00
|
|
|
const Pointer &Field = This.atField(FieldOffset);
|
[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 auto &Value = S.Stk.pop<T>();
|
|
|
|
Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-09-16 19:11:58 +02:00
|
|
|
/// 1) Pops the value from the stack
|
2022-10-21 15:43:42 +02:00
|
|
|
/// 2) Peeks a pointer from the stack
|
2022-09-23 11:29:33 +02:00
|
|
|
/// 3) Pushes the value to field I of the pointer on the stack
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
2022-10-21 15:43:42 +02:00
|
|
|
const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
|
[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
|
|
|
Field.deref<T>() = Value;
|
|
|
|
Field.activate();
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
|
2023-08-10 09:19:05 +02:00
|
|
|
assert(F->isBitField());
|
[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 T &Value = S.Stk.pop<T>();
|
2023-08-10 09:19:05 +02:00
|
|
|
const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
|
[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
|
|
|
Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
|
|
|
|
Field.activate();
|
|
|
|
Field.initialize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// GetPtr Local/Param/Global/Field/This
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
if (S.checkingPotentialConstantExpression()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
S.Stk.push<Pointer>(S.Current->getParamPointer(I));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-06-07 09:24:33 +02:00
|
|
|
/// 1) Peeks a Pointer
|
2022-09-23 11:29:33 +02:00
|
|
|
/// 2) Pushes Pointer.atField(Off) on the stack
|
[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
|
|
|
inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
2024-06-07 09:24:33 +02:00
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
|
|
|
|
!CheckNull(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!CheckExtern(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckArray(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
|
|
|
|
return false;
|
2024-08-06 13:37:11 +02:00
|
|
|
|
|
|
|
if (Ptr.isIntegralPointer()) {
|
|
|
|
S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-06-07 09:24:33 +02:00
|
|
|
S.Stk.push<Pointer>(Ptr.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
[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 Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-02-12 13:00:36 +01:00
|
|
|
|
2024-03-06 11:28:19 +01:00
|
|
|
if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
|
|
|
|
!CheckNull(S, OpPC, Ptr, CSK_Field))
|
[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
|
|
|
return false;
|
2023-04-25 14:30:28 +02:00
|
|
|
|
2024-05-11 06:13:15 +02:00
|
|
|
if (!CheckExtern(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
2024-05-16 21:26:59 +02:00
|
|
|
if (!CheckArray(S, OpPC, Ptr))
|
|
|
|
return false;
|
2024-05-11 06:13:15 +02:00
|
|
|
if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
|
|
|
|
return false;
|
|
|
|
|
2024-08-06 13:37:11 +02:00
|
|
|
if (Ptr.isIntegralPointer()) {
|
|
|
|
S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
S.Stk.push<Pointer>(Ptr.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(This.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
|
|
|
|
return false;
|
|
|
|
Pointer Field = Ptr.atField(Off);
|
|
|
|
Ptr.deactivate();
|
|
|
|
Field.activate();
|
|
|
|
S.Stk.push<Pointer>(std::move(Field));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
2024-08-16 17:13:12 +02:00
|
|
|
if (S.checkingPotentialConstantExpression())
|
[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
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
Pointer Field = This.atField(Off);
|
|
|
|
This.deactivate();
|
|
|
|
Field.activate();
|
|
|
|
S.Stk.push<Pointer>(std::move(Field));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-04-24 16:45:16 +02:00
|
|
|
inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
|
|
|
|
return false;
|
2023-04-25 14:30:28 +02:00
|
|
|
if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
|
2023-04-24 16:45:16 +02:00
|
|
|
return false;
|
2024-06-06 11:17:48 +02:00
|
|
|
if (!CheckDowncast(S, OpPC, Ptr, Off))
|
|
|
|
return false;
|
|
|
|
|
2023-04-24 16:45:16 +02:00
|
|
|
S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
2023-01-05 12:55:29 +01:00
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
|
|
|
|
return false;
|
2023-04-25 14:30:28 +02:00
|
|
|
if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
|
2023-04-24 16:45:16 +02:00
|
|
|
return false;
|
2024-07-25 13:35:16 +02:00
|
|
|
const Pointer &Result = Ptr.atField(Off);
|
|
|
|
if (Result.isPastEnd())
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(Result);
|
2023-01-05 12:55:29 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
[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 Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
|
|
|
|
return false;
|
2023-04-25 14:30:28 +02:00
|
|
|
if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
|
2023-04-24 16:45:16 +02:00
|
|
|
return false;
|
2024-07-25 13:35:16 +02:00
|
|
|
const Pointer &Result = Ptr.atField(Off);
|
|
|
|
if (Result.isPastEnd())
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(Result);
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-06-06 11:17:48 +02:00
|
|
|
inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
|
|
|
|
const auto &Ptr = S.Stk.pop<MemberPointer>();
|
|
|
|
S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
S.Stk.push<Pointer>(This.atField(Off));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-02-27 07:36:01 +01:00
|
|
|
inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
|
2023-10-03 06:46:31 +02:00
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2024-05-23 14:01:32 +02:00
|
|
|
if (Ptr.canBeInitialized()) {
|
2024-02-10 17:42:36 +01:00
|
|
|
Ptr.initialize();
|
2024-05-23 14:01:32 +02:00
|
|
|
Ptr.activate();
|
|
|
|
}
|
2023-10-03 06:46:31 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-02-27 07:36:01 +01:00
|
|
|
inline bool FinishInit(InterpState &S, CodePtr OpPC) {
|
2024-01-31 08:03:37 +01:00
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
2024-05-23 14:01:32 +02:00
|
|
|
if (Ptr.canBeInitialized()) {
|
2024-02-10 17:42:36 +01:00
|
|
|
Ptr.initialize();
|
2024-05-23 14:01:32 +02:00
|
|
|
Ptr.activate();
|
|
|
|
}
|
2024-01-31 08:03:37 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-03 07:57:26 +02:00
|
|
|
inline bool Dump(InterpState &S, CodePtr OpPC) {
|
|
|
|
S.Stk.dump();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
|
|
|
|
const Pointer &Ptr) {
|
|
|
|
Pointer Base = Ptr;
|
|
|
|
while (Base.isBaseClass())
|
|
|
|
Base = Base.getBase();
|
|
|
|
|
2024-04-25 07:39:41 +02:00
|
|
|
const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
|
|
|
|
S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-25 07:39:41 +02:00
|
|
|
inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
|
|
|
|
const RecordDecl *D) {
|
|
|
|
assert(D);
|
[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 Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
|
|
|
|
return false;
|
|
|
|
return VirtBaseHelper(S, OpPC, D, Ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
|
|
|
|
const RecordDecl *D) {
|
2024-04-25 07:39:41 +02:00
|
|
|
assert(D);
|
[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 (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Load, Store, Init
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Load(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckLoad(S, OpPC, Ptr))
|
|
|
|
return false;
|
2024-04-10 12:53:54 +02:00
|
|
|
if (!Ptr.isBlockPointer())
|
|
|
|
return false;
|
[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
|
|
|
S.Stk.push<T>(Ptr.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool LoadPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckLoad(S, OpPC, Ptr))
|
|
|
|
return false;
|
2024-04-10 12:53:54 +02:00
|
|
|
if (!Ptr.isBlockPointer())
|
|
|
|
return false;
|
[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
|
|
|
S.Stk.push<T>(Ptr.deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Store(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckStore(S, OpPC, Ptr))
|
|
|
|
return false;
|
2024-08-10 09:09:12 +02:00
|
|
|
if (Ptr.canBeInitialized()) {
|
2022-12-26 09:29:04 +01:00
|
|
|
Ptr.initialize();
|
2024-08-10 09:09:12 +02:00
|
|
|
Ptr.activate();
|
|
|
|
}
|
[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
|
|
|
Ptr.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool StorePop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckStore(S, OpPC, Ptr))
|
|
|
|
return false;
|
2024-08-10 09:09:12 +02:00
|
|
|
if (Ptr.canBeInitialized()) {
|
2022-12-26 09:29:04 +01:00
|
|
|
Ptr.initialize();
|
2024-08-10 09:09:12 +02:00
|
|
|
Ptr.activate();
|
|
|
|
}
|
[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
|
|
|
Ptr.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool StoreBitField(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckStore(S, OpPC, Ptr))
|
|
|
|
return false;
|
2024-01-31 08:03:37 +01:00
|
|
|
if (Ptr.canBeInitialized())
|
2022-12-26 09:29:04 +01:00
|
|
|
Ptr.initialize();
|
2023-08-10 09:19:05 +02:00
|
|
|
if (const auto *FD = Ptr.getField())
|
[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
|
|
|
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
|
2023-08-10 09:19:05 +02:00
|
|
|
else
|
[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
|
|
|
Ptr.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckStore(S, OpPC, Ptr))
|
|
|
|
return false;
|
2024-01-31 08:03:37 +01:00
|
|
|
if (Ptr.canBeInitialized())
|
2022-12-26 09:29:04 +01:00
|
|
|
Ptr.initialize();
|
2023-08-10 09:19:05 +02:00
|
|
|
if (const auto *FD = Ptr.getField())
|
[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
|
|
|
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
|
2023-08-10 09:19:05 +02:00
|
|
|
else
|
[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
|
|
|
Ptr.deref<T>() = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-02-27 07:36:46 +01:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Init(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
if (!CheckInit(S, OpPC, Ptr)) {
|
|
|
|
assert(false);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Ptr.initialize();
|
|
|
|
new (&Ptr.deref<T>()) T(Value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
if (!CheckInit(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
Ptr.initialize();
|
|
|
|
new (&Ptr.deref<T>()) T(Value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-31 16:09:40 +02:00
|
|
|
/// 1) Pops the value from the stack
|
|
|
|
/// 2) Peeks a pointer and gets its index \Idx
|
|
|
|
/// 3) Sets the value on the pointer, leaving the pointer on the stack.
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
|
2024-03-04 06:26:39 +01:00
|
|
|
if (Ptr.isUnknownSizeArray())
|
|
|
|
return false;
|
[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 (!CheckInit(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
Ptr.initialize();
|
|
|
|
new (&Ptr.deref<T>()) T(Value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-31 16:09:40 +02:00
|
|
|
/// The same as InitElem, but pops the pointer as well.
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
|
|
|
|
const T &Value = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
|
2024-03-04 06:26:39 +01:00
|
|
|
if (Ptr.isUnknownSizeArray())
|
|
|
|
return false;
|
[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 (!CheckInit(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
Ptr.initialize();
|
|
|
|
new (&Ptr.deref<T>()) T(Value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-03-12 15:27:35 +01:00
|
|
|
inline bool Memcpy(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Src = S.Stk.pop<Pointer>();
|
|
|
|
Pointer &Dest = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
if (!CheckLoad(S, OpPC, Src))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return DoMemcpy(S, OpPC, Src, Dest);
|
|
|
|
}
|
|
|
|
|
2024-06-06 11:17:48 +02:00
|
|
|
inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const auto &Member = S.Stk.pop<MemberPointer>();
|
|
|
|
const auto &Base = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
S.Stk.push<MemberPointer>(Member.takeInstance(Base));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const auto &MP = S.Stk.pop<MemberPointer>();
|
|
|
|
|
|
|
|
if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
|
|
|
|
S.Stk.push<Pointer>(*Ptr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// AddOffset, SubOffset
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-12-31 16:44:41 +01:00
|
|
|
template <class T, ArithOp Op>
|
|
|
|
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
|
|
|
|
const Pointer &Ptr) {
|
2022-10-13 10:09:36 +02:00
|
|
|
// A zero offset does not change the pointer.
|
[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 (Offset.isZero()) {
|
2022-10-13 10:09:36 +02:00
|
|
|
S.Stk.push<Pointer>(Ptr);
|
[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
|
|
|
return true;
|
|
|
|
}
|
2022-10-13 10:09:36 +02:00
|
|
|
|
2024-04-10 12:53:54 +02:00
|
|
|
if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
|
|
|
|
// The CheckNull will have emitted a note already, but we only
|
|
|
|
// abort in C++, since this is fine in C.
|
|
|
|
if (S.getLangOpts().CPlusPlus)
|
|
|
|
return false;
|
|
|
|
}
|
2022-10-13 10:09:36 +02:00
|
|
|
|
[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
|
|
|
// Arrays of unknown bounds cannot have pointers into them.
|
|
|
|
if (!CheckArray(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
|
2024-08-18 08:59:34 +02:00
|
|
|
// This is much simpler for integral pointers, so handle them first.
|
|
|
|
if (Ptr.isIntegralPointer()) {
|
|
|
|
uint64_t V = Ptr.getIntegerRepresentation();
|
|
|
|
uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
|
|
|
|
if constexpr (Op == ArithOp::Add)
|
|
|
|
S.Stk.push<Pointer>(V + O, Ptr.asIntPointer().Desc);
|
|
|
|
else
|
|
|
|
S.Stk.push<Pointer>(V - O, Ptr.asIntPointer().Desc);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-19 17:31:28 +02:00
|
|
|
uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
|
2024-05-21 12:59:03 +02:00
|
|
|
uint64_t Index;
|
|
|
|
if (Ptr.isOnePastEnd())
|
|
|
|
Index = MaxIndex;
|
|
|
|
else
|
|
|
|
Index = Ptr.getIndex();
|
[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
|
|
|
|
2023-10-26 15:15:25 +02:00
|
|
|
bool Invalid = false;
|
[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
|
|
|
// Helper to report an invalid offset, computed as APSInt.
|
2023-10-26 15:15:25 +02:00
|
|
|
auto DiagInvalidOffset = [&]() -> void {
|
[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 unsigned Bits = Offset.bitWidth();
|
2024-04-19 17:31:28 +02:00
|
|
|
APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
|
|
|
|
APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
|
|
|
|
/*IsUnsigned=*/false);
|
2022-12-31 16:44:41 +01:00
|
|
|
APSInt NewIndex =
|
|
|
|
(Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
|
[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
|
|
|
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
|
2024-05-14 11:17:49 +02:00
|
|
|
<< NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
|
2023-10-26 15:15:25 +02:00
|
|
|
Invalid = true;
|
[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
|
|
|
};
|
|
|
|
|
2024-04-10 12:53:54 +02:00
|
|
|
if (Ptr.isBlockPointer()) {
|
2024-04-19 17:31:28 +02:00
|
|
|
uint64_t IOffset = static_cast<uint64_t>(Offset);
|
|
|
|
uint64_t MaxOffset = MaxIndex - Index;
|
|
|
|
|
2024-04-10 12:53:54 +02:00
|
|
|
if constexpr (Op == ArithOp::Add) {
|
|
|
|
// If the new offset would be negative, bail out.
|
2024-04-19 17:31:28 +02:00
|
|
|
if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
|
2024-04-10 12:53:54 +02:00
|
|
|
DiagInvalidOffset();
|
|
|
|
|
|
|
|
// If the new offset would be out of bounds, bail out.
|
2024-04-19 17:31:28 +02:00
|
|
|
if (Offset.isPositive() && IOffset > MaxOffset)
|
2024-04-10 12:53:54 +02:00
|
|
|
DiagInvalidOffset();
|
|
|
|
} else {
|
|
|
|
// If the new offset would be negative, bail out.
|
2024-04-19 17:31:28 +02:00
|
|
|
if (Offset.isPositive() && Index < IOffset)
|
2024-04-10 12:53:54 +02:00
|
|
|
DiagInvalidOffset();
|
|
|
|
|
|
|
|
// If the new offset would be out of bounds, bail out.
|
2024-04-19 17:31:28 +02:00
|
|
|
if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
|
2024-04-10 12:53:54 +02:00
|
|
|
DiagInvalidOffset();
|
|
|
|
}
|
2022-09-11 14:39:52 +02:00
|
|
|
}
|
[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
|
|
|
|
2024-05-14 11:17:49 +02:00
|
|
|
if (Invalid && S.getLangOpts().CPlusPlus)
|
2023-10-26 15:15:25 +02:00
|
|
|
return false;
|
|
|
|
|
[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
|
|
|
// Offset is valid - compute it on unsigned.
|
|
|
|
int64_t WideIndex = static_cast<int64_t>(Index);
|
|
|
|
int64_t WideOffset = static_cast<int64_t>(Offset);
|
2022-11-09 12:48:43 +01:00
|
|
|
int64_t Result;
|
2022-12-31 16:44:41 +01:00
|
|
|
if constexpr (Op == ArithOp::Add)
|
2022-11-09 12:48:43 +01:00
|
|
|
Result = WideIndex + WideOffset;
|
|
|
|
else
|
|
|
|
Result = WideIndex - WideOffset;
|
|
|
|
|
2024-07-13 06:57:51 +02:00
|
|
|
// When the pointer is one-past-end, going back to index 0 is the only
|
|
|
|
// useful thing we can do. Any other index has been diagnosed before and
|
|
|
|
// we don't get here.
|
|
|
|
if (Result == 0 && Ptr.isOnePastEnd()) {
|
|
|
|
S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,
|
|
|
|
Ptr.asBlockPointer().Base);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-19 17:31:28 +02:00
|
|
|
S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool AddOffset(InterpState &S, CodePtr OpPC) {
|
2022-12-31 16:44:41 +01:00
|
|
|
const T &Offset = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
|
[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
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool SubOffset(InterpState &S, CodePtr OpPC) {
|
2022-12-31 16:44:41 +01:00
|
|
|
const T &Offset = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
|
[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
|
|
|
}
|
|
|
|
|
2022-11-02 09:09:23 +01:00
|
|
|
template <ArithOp Op>
|
2023-08-24 07:03:53 +02:00
|
|
|
static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
|
|
|
|
const Pointer &Ptr) {
|
2024-01-31 14:36:23 +01:00
|
|
|
if (Ptr.isDummy())
|
|
|
|
return false;
|
|
|
|
|
2022-11-02 09:09:23 +01:00
|
|
|
using OneT = Integral<8, false>;
|
|
|
|
|
2023-10-17 06:53:33 +02:00
|
|
|
const Pointer &P = Ptr.deref<Pointer>();
|
|
|
|
if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
|
|
|
|
return false;
|
|
|
|
|
2022-11-02 09:09:23 +01:00
|
|
|
// Get the current value on the stack.
|
2023-10-17 06:53:33 +02:00
|
|
|
S.Stk.push<Pointer>(P);
|
2022-11-02 09:09:23 +01:00
|
|
|
|
|
|
|
// Now the current Ptr again and a constant 1.
|
2022-12-31 16:44:41 +01:00
|
|
|
OneT One = OneT::from(1);
|
|
|
|
if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
|
2022-11-02 09:09:23 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Store the new value.
|
|
|
|
Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
|
2023-08-24 07:03:53 +02:00
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
|
2022-11-02 09:09:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
|
2023-08-24 07:03:53 +02:00
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
|
2022-11-02 09:09:23 +01:00
|
|
|
}
|
|
|
|
|
2022-10-13 10:09:36 +02:00
|
|
|
/// 1) Pops a Pointer from the stack.
|
|
|
|
/// 2) Pops another Pointer from the stack.
|
|
|
|
/// 3) Pushes the different of the indices of the two pointers on the stack.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool SubPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &LHS = S.Stk.pop<Pointer>();
|
|
|
|
const Pointer &RHS = S.Stk.pop<Pointer>();
|
|
|
|
|
2024-08-14 10:05:06 +02:00
|
|
|
for (const Pointer &P : {LHS, RHS}) {
|
|
|
|
if (P.isZeroSizeArray()) {
|
|
|
|
QualType PtrT = P.getType();
|
|
|
|
while (auto *AT = dyn_cast<ArrayType>(PtrT))
|
|
|
|
PtrT = AT->getElementType();
|
|
|
|
|
|
|
|
QualType ArrayTy = S.getCtx().getConstantArrayType(
|
|
|
|
PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
|
|
|
|
S.FFDiag(S.Current->getSource(OpPC),
|
|
|
|
diag::note_constexpr_pointer_subtraction_zero_size)
|
|
|
|
<< ArrayTy;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-10 12:53:54 +02:00
|
|
|
if (RHS.isZero()) {
|
|
|
|
S.Stk.push<T>(T::from(LHS.getIndex()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-11-15 08:03:06 +01:00
|
|
|
if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
|
2022-10-13 10:09:36 +02:00
|
|
|
// TODO: Diagnose.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-02-19 16:29:46 +01:00
|
|
|
if (LHS.isZero() && RHS.isZero()) {
|
|
|
|
S.Stk.push<T>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-06-06 11:20:13 +02:00
|
|
|
T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
|
|
|
|
: T::from(LHS.getIndex());
|
|
|
|
T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
|
|
|
|
: T::from(RHS.getIndex());
|
2022-10-13 10:09:36 +02:00
|
|
|
return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
|
|
|
|
}
|
[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
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Destroy
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Current->destroy(I);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-08-03 08:25:44 +02:00
|
|
|
inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
|
|
|
|
S.Current->initScope(I);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Cast, CastFP
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
|
|
|
|
using T = typename PrimConv<TIn>::T;
|
|
|
|
using U = typename PrimConv<TOut>::T;
|
|
|
|
S.Stk.push<U>(U::from(S.Stk.pop<T>()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
/// 1) Pops a Floating from the stack.
|
|
|
|
/// 2) Pushes a new floating on the stack that uses the given semantics.
|
2023-07-03 12:43:20 +02:00
|
|
|
inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
|
2024-08-16 17:13:12 +02:00
|
|
|
llvm::RoundingMode RM) {
|
2023-07-03 12:43:20 +02:00
|
|
|
Floating F = S.Stk.pop<Floating>();
|
|
|
|
Floating Result = F.toSemantics(Sem, RM);
|
|
|
|
S.Stk.push<Floating>(Result);
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-25 14:51:16 +01:00
|
|
|
|
2023-10-11 08:53:21 +02:00
|
|
|
/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
|
|
|
|
/// to know what bitwidth the result should be.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
|
|
|
|
S.Stk.push<IntegralAP<false>>(
|
|
|
|
IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
|
|
|
|
S.Stk.push<IntegralAP<true>>(
|
|
|
|
IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-01-25 14:51:16 +01:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
|
|
|
|
const llvm::fltSemantics *Sem,
|
|
|
|
llvm::RoundingMode RM) {
|
|
|
|
const T &From = S.Stk.pop<T>();
|
|
|
|
APSInt FromAP = From.toAPSInt();
|
|
|
|
Floating Result;
|
|
|
|
|
|
|
|
auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
|
|
|
|
S.Stk.push<Floating>(Result);
|
|
|
|
|
2023-07-28 08:07:51 +02:00
|
|
|
return CheckFloatResult(S, OpPC, Result, Status);
|
2023-01-25 14:51:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Floating &F = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
if constexpr (std::is_same_v<T, Boolean>) {
|
|
|
|
S.Stk.push<T>(T(F.isNonZero()));
|
|
|
|
return true;
|
|
|
|
} else {
|
2023-09-30 20:12:59 +02:00
|
|
|
APSInt Result(std::max(8u, T::bitWidth()),
|
2023-01-25 14:51:16 +01:00
|
|
|
/*IsUnsigned=*/!T::isSigned());
|
|
|
|
auto Status = F.convertToInteger(Result);
|
|
|
|
|
|
|
|
// Float-to-Integral overflow check.
|
2024-02-28 16:14:49 +01:00
|
|
|
if ((Status & APFloat::opStatus::opInvalidOp)) {
|
2023-01-25 14:51:16 +01:00
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
|
2023-12-11 17:25:03 +01:00
|
|
|
if (S.noteUndefinedBehavior()) {
|
|
|
|
S.Stk.push<T>(T(Result));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2023-01-25 14:51:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
S.Stk.push<T>(T(Result));
|
2023-07-28 08:07:51 +02:00
|
|
|
return CheckFloatResult(S, OpPC, F, Status);
|
2023-01-25 14:51:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-11 08:53:21 +02:00
|
|
|
static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
|
|
|
|
uint32_t BitWidth) {
|
|
|
|
const Floating &F = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
APSInt Result(BitWidth, /*IsUnsigned=*/true);
|
|
|
|
auto Status = F.convertToInteger(Result);
|
|
|
|
|
|
|
|
// Float-to-Integral overflow check.
|
|
|
|
if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
|
|
|
|
return S.noteUndefinedBehavior();
|
|
|
|
}
|
|
|
|
|
|
|
|
S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
|
|
|
|
return CheckFloatResult(S, OpPC, F, Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
|
|
|
|
uint32_t BitWidth) {
|
|
|
|
const Floating &F = S.Stk.pop<Floating>();
|
|
|
|
|
|
|
|
APSInt Result(BitWidth, /*IsUnsigned=*/false);
|
|
|
|
auto Status = F.convertToInteger(Result);
|
|
|
|
|
|
|
|
// Float-to-Integral overflow check.
|
|
|
|
if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
QualType Type = E->getType();
|
|
|
|
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
|
|
|
|
return S.noteUndefinedBehavior();
|
|
|
|
}
|
|
|
|
|
|
|
|
S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
|
|
|
|
return CheckFloatResult(S, OpPC, F, Status);
|
|
|
|
}
|
|
|
|
|
2023-05-19 11:12:05 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2024-06-09 21:13:55 +02:00
|
|
|
if (Ptr.isDummy())
|
|
|
|
return false;
|
|
|
|
|
2024-02-16 14:30:34 +01:00
|
|
|
const SourceInfo &E = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
|
|
|
|
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
|
2023-05-19 11:12:05 +02:00
|
|
|
|
|
|
|
S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-22 11:34:05 +02:00
|
|
|
static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
|
|
|
|
uint32_t BitWidth) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2024-06-09 21:13:55 +02:00
|
|
|
if (Ptr.isDummy())
|
|
|
|
return false;
|
|
|
|
|
2024-04-22 11:34:05 +02:00
|
|
|
const SourceInfo &E = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
|
|
|
|
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
|
|
|
|
|
|
|
|
S.Stk.push<IntegralAP<false>>(
|
|
|
|
IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
|
|
|
|
uint32_t BitWidth) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2024-06-09 21:13:55 +02:00
|
|
|
if (Ptr.isDummy())
|
|
|
|
return false;
|
|
|
|
|
2024-04-22 11:34:05 +02:00
|
|
|
const SourceInfo &E = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
|
|
|
|
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
|
|
|
|
|
|
|
|
S.Stk.push<IntegralAP<true>>(
|
|
|
|
IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-06-11 06:14:17 +02:00
|
|
|
static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
|
|
|
|
const auto &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
|
|
|
|
bool HasValidResult = !Ptr.isZero();
|
|
|
|
|
|
|
|
if (HasValidResult) {
|
|
|
|
// FIXME: note_constexpr_invalid_void_star_cast
|
|
|
|
} else if (!S.getLangOpts().CPlusPlus26) {
|
|
|
|
const SourceInfo &E = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
|
|
|
|
<< 3 << "'void *'" << S.Current->getRange(OpPC);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const SourceInfo &E = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
|
|
|
|
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
|
|
|
|
}
|
|
|
|
|
2024-06-10 10:10:43 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Zero, Nullptr
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
bool Zero(InterpState &S, CodePtr OpPC) {
|
|
|
|
S.Stk.push<T>(T::zero());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-10-19 08:20:53 +02:00
|
|
|
static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
|
|
|
|
S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
|
|
|
|
S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
2024-04-10 12:53:54 +02:00
|
|
|
inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
|
|
|
|
// Note: Desc can be null.
|
|
|
|
S.Stk.push<T>(0, Desc);
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// This, ImplicitThis
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool This(InterpState &S, CodePtr OpPC) {
|
|
|
|
// Cannot read 'this' in this mode.
|
|
|
|
if (S.checkingPotentialConstantExpression()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Pointer &This = S.Current->getThis();
|
|
|
|
if (!CheckThis(S, OpPC, This))
|
|
|
|
return false;
|
|
|
|
|
2024-04-05 16:58:35 +02:00
|
|
|
// Ensure the This pointer has been cast to the correct base.
|
|
|
|
if (!This.isDummy()) {
|
|
|
|
assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
|
|
|
|
assert(This.getRecord());
|
|
|
|
assert(
|
|
|
|
This.getRecord()->getDecl() ==
|
|
|
|
cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
S.Stk.push<Pointer>(This);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-04 07:43:34 +01:00
|
|
|
inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
assert(S.Current->getFunction()->hasRVO());
|
2022-12-28 09:34:47 +01:00
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
2022-11-04 07:43:34 +01:00
|
|
|
S.Stk.push<Pointer>(S.Current->getRVOPtr());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Shr, Shl
|
|
|
|
//===----------------------------------------------------------------------===//
|
2024-07-14 03:08:02 +02:00
|
|
|
enum class ShiftDir { Left, Right };
|
[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
|
|
|
|
2024-07-14 03:08:02 +02:00
|
|
|
template <class LT, class RT, ShiftDir Dir>
|
|
|
|
inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
|
2022-10-22 18:19:10 +02:00
|
|
|
const unsigned Bits = LHS.bitWidth();
|
|
|
|
|
2024-04-30 06:18:31 +02:00
|
|
|
// OpenCL 6.3j: shift values are effectively % word size of LHS.
|
|
|
|
if (S.getLangOpts().OpenCL)
|
|
|
|
RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
|
|
|
|
RHS.bitWidth(), &RHS);
|
|
|
|
|
2024-07-14 03:08:02 +02:00
|
|
|
if (RHS.isNegative()) {
|
|
|
|
// During constant-folding, a negative shift is an opposite shift. Such a
|
|
|
|
// shift is not a constant expression.
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
|
2024-07-24 12:36:08 -07:00
|
|
|
if (!S.noteUndefinedBehavior())
|
2024-07-14 03:08:02 +02:00
|
|
|
return false;
|
|
|
|
RHS = -RHS;
|
2024-08-16 17:13:12 +02:00
|
|
|
return DoShift<LT, RT,
|
|
|
|
Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
|
|
|
|
S, OpPC, LHS, RHS);
|
2024-07-14 03:08:02 +02:00
|
|
|
}
|
|
|
|
|
2024-07-14 06:46:04 +02:00
|
|
|
if constexpr (Dir == ShiftDir::Left) {
|
|
|
|
if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) {
|
|
|
|
// C++11 [expr.shift]p2: A signed left shift must have a non-negative
|
|
|
|
// operand, and must not overflow the corresponding unsigned type.
|
|
|
|
// C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
|
|
|
|
// E1 x 2^E2 module 2^N.
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
|
2024-07-24 12:36:08 -07:00
|
|
|
if (!S.noteUndefinedBehavior())
|
2024-07-14 06:46:04 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-09 19:38:37 +02:00
|
|
|
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
|
Revert "[clang][Interp][NFC] Remove shift error checking code duplication"
This reverts commit fddf6418e8492a544c9bfdb42a4dbc949d9dc2ee.
Apparently this also breaks some builders:
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x1f54): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<16u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<16u, true> const&, unsigned int)'
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x1fd4): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<32u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<32u, true> const&, unsigned int)'
/usr/bin/ld: EvalEmitter.cpp:(.text._ZN5clang6interp11EvalEmitter7emitShlENS0_8PrimTypeES2_RKNS0_10SourceInfoE+0x2058): undefined reference to `bool clang::interp::CheckShift<clang::interp::Integral<32u, true> >(clang::interp::InterpState&, clang::interp::CodePtr, clang::interp::Integral<32u, true> const&, unsigned int)'
(etc)
2023-01-19 13:03:20 +01:00
|
|
|
return false;
|
[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
|
|
|
|
2024-02-20 08:55:52 +01:00
|
|
|
// Limit the shift amount to Bits - 1. If this happened,
|
|
|
|
// it has already been diagnosed by CheckShift() above,
|
|
|
|
// but we still need to handle it.
|
2023-09-30 20:12:59 +02:00
|
|
|
typename LT::AsUnsigned R;
|
2024-07-14 03:08:02 +02:00
|
|
|
if constexpr (Dir == ShiftDir::Left) {
|
|
|
|
if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
|
|
|
|
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
|
|
|
|
LT::AsUnsigned::from(Bits - 1), Bits, &R);
|
|
|
|
else
|
|
|
|
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
|
|
|
|
LT::AsUnsigned::from(RHS, Bits), Bits, &R);
|
|
|
|
} else {
|
|
|
|
if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
|
|
|
|
LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
|
|
|
|
LT::AsUnsigned::from(Bits - 1), Bits, &R);
|
|
|
|
else
|
|
|
|
LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
|
|
|
|
LT::AsUnsigned::from(RHS, Bits), Bits, &R);
|
|
|
|
}
|
|
|
|
|
2024-08-17 22:57:19 +02:00
|
|
|
// We did the shift above as unsigned. Restore the sign bit if we need to.
|
|
|
|
if constexpr (Dir == ShiftDir::Right) {
|
|
|
|
if (LHS.isSigned() && LHS.isNegative()) {
|
|
|
|
typename LT::AsUnsigned SignBit;
|
|
|
|
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(1, Bits),
|
|
|
|
LT::AsUnsigned::from(Bits - 1, Bits), Bits,
|
|
|
|
&SignBit);
|
|
|
|
LT::AsUnsigned::bitOr(R, SignBit, Bits, &R);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-30 20:12:59 +02:00
|
|
|
S.Stk.push<LT>(LT::from(R));
|
[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
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-22 18:19:10 +02:00
|
|
|
template <PrimType NameL, PrimType NameR>
|
2024-07-14 03:08:02 +02:00
|
|
|
inline bool Shr(InterpState &S, CodePtr OpPC) {
|
2022-10-22 18:19:10 +02:00
|
|
|
using LT = typename PrimConv<NameL>::T;
|
|
|
|
using RT = typename PrimConv<NameR>::T;
|
2024-04-30 06:18:31 +02:00
|
|
|
auto RHS = S.Stk.pop<RT>();
|
2024-07-14 03:08:02 +02:00
|
|
|
auto LHS = S.Stk.pop<LT>();
|
2024-04-30 06:18:31 +02:00
|
|
|
|
2024-07-14 03:08:02 +02:00
|
|
|
return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
|
|
|
|
}
|
2022-10-22 18:19:10 +02:00
|
|
|
|
2024-07-14 03:08:02 +02:00
|
|
|
template <PrimType NameL, PrimType NameR>
|
|
|
|
inline bool Shl(InterpState &S, CodePtr OpPC) {
|
|
|
|
using LT = typename PrimConv<NameL>::T;
|
|
|
|
using RT = typename PrimConv<NameR>::T;
|
|
|
|
auto RHS = S.Stk.pop<RT>();
|
|
|
|
auto LHS = S.Stk.pop<LT>();
|
2024-02-20 08:55:52 +01:00
|
|
|
|
2024-07-14 03:08:02 +02:00
|
|
|
return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
|
[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
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// NoRet
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool NoRet(InterpState &S, CodePtr OpPC) {
|
|
|
|
SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
|
|
|
|
S.FFDiag(EndLoc, diag::note_constexpr_no_return);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// NarrowPtr, ExpandPtr
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
S.Stk.push<Pointer>(Ptr.narrow());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
S.Stk.push<Pointer>(Ptr.expand());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-12-31 17:06:52 +01:00
|
|
|
// 1) Pops an integral value from the stack
|
|
|
|
// 2) Peeks a pointer
|
|
|
|
// 3) Pushes a new pointer that's a narrowed array
|
|
|
|
// element of the peeked pointer with the value
|
|
|
|
// from 1) added as offset.
|
|
|
|
//
|
|
|
|
// This leaves the original pointer on the stack and pushes a new one
|
|
|
|
// with the offset applied and narrowed.
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Offset = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
|
2024-08-08 15:03:03 +02:00
|
|
|
if (!Ptr.isZero() && !Offset.isZero()) {
|
2024-03-14 09:56:56 +01:00
|
|
|
if (!CheckArray(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
}
|
2024-02-06 12:02:08 +01:00
|
|
|
|
|
|
|
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return NarrowPtr(S, OpPC);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Offset = S.Stk.pop<T>();
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2024-08-08 15:03:03 +02:00
|
|
|
if (!Ptr.isZero() && !Offset.isZero()) {
|
2024-03-14 09:56:56 +01:00
|
|
|
if (!CheckArray(S, OpPC, Ptr))
|
|
|
|
return false;
|
2024-02-09 15:39:36 +01:00
|
|
|
}
|
2024-02-06 12:02:08 +01:00
|
|
|
|
2022-12-31 17:06:52 +01:00
|
|
|
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return NarrowPtr(S, OpPC);
|
|
|
|
}
|
|
|
|
|
2024-03-07 17:29:42 +01:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
|
|
|
|
const Pointer &Ptr = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
if (!CheckLoad(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-02-07 07:47:02 +01:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
2024-03-07 17:29:42 +01:00
|
|
|
if (!CheckLoad(S, OpPC, Ptr))
|
|
|
|
return false;
|
|
|
|
|
2024-02-07 07:47:02 +01:00
|
|
|
S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-30 08:30:22 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
2024-08-16 17:13:12 +02:00
|
|
|
inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
|
|
|
|
uint32_t DestIndex, uint32_t Size) {
|
2024-04-30 08:30:22 +02:00
|
|
|
const auto &SrcPtr = S.Stk.pop<Pointer>();
|
|
|
|
const auto &DestPtr = S.Stk.peek<Pointer>();
|
|
|
|
|
|
|
|
for (uint32_t I = 0; I != Size; ++I) {
|
|
|
|
const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
|
|
|
|
|
|
|
|
if (!CheckLoad(S, OpPC, SP))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const Pointer &DP = DestPtr.atIndex(DestIndex + I);
|
|
|
|
DP.deref<T>() = SP.deref<T>();
|
|
|
|
DP.initialize();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-02-06 12:37:27 +01:00
|
|
|
/// Just takes a pointer and checks if it's an incomplete
|
2023-10-26 13:53:54 +02:00
|
|
|
/// array type.
|
|
|
|
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
|
2023-12-12 11:01:47 +01:00
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
2023-10-26 13:53:54 +02:00
|
|
|
|
2024-05-11 06:13:15 +02:00
|
|
|
if (Ptr.isZero()) {
|
2024-02-12 13:00:36 +01:00
|
|
|
S.Stk.push<Pointer>(Ptr);
|
|
|
|
return true;
|
|
|
|
}
|
2024-02-09 10:11:51 +01:00
|
|
|
|
2024-05-14 11:17:49 +02:00
|
|
|
if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
|
|
|
|
return false;
|
|
|
|
|
2024-06-06 17:41:20 +02:00
|
|
|
if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
|
2023-12-12 11:01:47 +01:00
|
|
|
S.Stk.push<Pointer>(Ptr.atIndex(0));
|
2023-10-26 13:53:54 +02:00
|
|
|
return true;
|
2023-12-12 11:01:47 +01:00
|
|
|
}
|
2023-10-26 13:53:54 +02:00
|
|
|
|
|
|
|
const SourceInfo &E = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-02-14 15:29:47 +01:00
|
|
|
inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
|
|
|
|
uint32_t VarArgSize) {
|
2022-10-07 15:49:37 +02:00
|
|
|
if (Func->hasThisPointer()) {
|
2024-02-14 15:29:47 +01:00
|
|
|
size_t ArgSize = Func->getArgSize() + VarArgSize;
|
|
|
|
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
|
|
|
|
const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
|
|
|
|
|
|
|
|
// If the current function is a lambda static invoker and
|
|
|
|
// the function we're about to call is a lambda call operator,
|
|
|
|
// skip the CheckInvoke, since the ThisPtr is a null pointer
|
|
|
|
// anyway.
|
|
|
|
if (!(S.Current->getFunction() &&
|
|
|
|
S.Current->getFunction()->isLambdaStaticInvoker() &&
|
|
|
|
Func->isLambdaCallOperator())) {
|
|
|
|
if (!CheckInvoke(S, OpPC, ThisPtr))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CheckCallable(S, OpPC, Func))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!CheckCallDepth(S, OpPC))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
|
|
|
|
InterpFrame *FrameBefore = S.Current;
|
|
|
|
S.Current = NewFrame.get();
|
|
|
|
|
|
|
|
APValue CallResult;
|
|
|
|
// Note that we cannot assert(CallResult.hasValue()) here since
|
|
|
|
// Ret() above only sets the APValue if the curent frame doesn't
|
|
|
|
// have a caller set.
|
|
|
|
if (Interpret(S, CallResult)) {
|
|
|
|
NewFrame.release(); // Frame was delete'd already.
|
|
|
|
assert(S.Current == FrameBefore);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interpreting the function failed somehow. Reset to
|
|
|
|
// previous state.
|
|
|
|
S.Current = FrameBefore;
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2024-02-25 14:03:47 +01:00
|
|
|
|
2024-02-14 15:29:47 +01:00
|
|
|
inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
|
|
|
|
uint32_t VarArgSize) {
|
|
|
|
if (Func->hasThisPointer()) {
|
|
|
|
size_t ArgSize = Func->getArgSize() + VarArgSize;
|
|
|
|
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
|
2023-02-03 12:20:15 +01:00
|
|
|
|
2023-01-26 14:07:46 +01:00
|
|
|
const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
|
|
|
|
|
2023-05-08 15:36:56 +02:00
|
|
|
// If the current function is a lambda static invoker and
|
|
|
|
// the function we're about to call is a lambda call operator,
|
|
|
|
// skip the CheckInvoke, since the ThisPtr is a null pointer
|
|
|
|
// anyway.
|
|
|
|
if (!(S.Current->getFunction() &&
|
|
|
|
S.Current->getFunction()->isLambdaStaticInvoker() &&
|
|
|
|
Func->isLambdaCallOperator())) {
|
|
|
|
if (!CheckInvoke(S, OpPC, ThisPtr))
|
|
|
|
return false;
|
|
|
|
}
|
2022-10-07 15:49:37 +02:00
|
|
|
}
|
2022-10-28 10:31:47 +02:00
|
|
|
|
2023-02-03 12:20:15 +01:00
|
|
|
if (!CheckCallable(S, OpPC, Func))
|
2022-10-28 10:31:47 +02:00
|
|
|
return false;
|
2022-10-07 15:49:37 +02:00
|
|
|
|
2024-07-18 15:30:42 +02:00
|
|
|
if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
|
|
|
|
return false;
|
|
|
|
|
2023-04-17 15:23:37 +02:00
|
|
|
if (!CheckCallDepth(S, OpPC))
|
|
|
|
return false;
|
|
|
|
|
2024-02-14 15:29:47 +01:00
|
|
|
auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
|
2022-10-07 15:49:37 +02:00
|
|
|
InterpFrame *FrameBefore = S.Current;
|
|
|
|
S.Current = NewFrame.get();
|
|
|
|
|
|
|
|
APValue CallResult;
|
|
|
|
// Note that we cannot assert(CallResult.hasValue()) here since
|
|
|
|
// Ret() above only sets the APValue if the curent frame doesn't
|
|
|
|
// have a caller set.
|
|
|
|
if (Interpret(S, CallResult)) {
|
|
|
|
NewFrame.release(); // Frame was delete'd already.
|
|
|
|
assert(S.Current == FrameBefore);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interpreting the function failed somehow. Reset to
|
|
|
|
// previous state.
|
|
|
|
S.Current = FrameBefore;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-02-14 15:29:47 +01:00
|
|
|
inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
|
|
|
|
uint32_t VarArgSize) {
|
2023-01-26 16:25:52 +01:00
|
|
|
assert(Func->hasThisPointer());
|
|
|
|
assert(Func->isVirtual());
|
2024-02-14 15:29:47 +01:00
|
|
|
size_t ArgSize = Func->getArgSize() + VarArgSize;
|
|
|
|
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
|
2023-01-26 16:25:52 +01:00
|
|
|
Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
|
|
|
|
|
2024-07-30 13:38:15 +02:00
|
|
|
const CXXRecordDecl *DynamicDecl = nullptr;
|
|
|
|
{
|
|
|
|
Pointer TypePtr = ThisPtr;
|
|
|
|
while (TypePtr.isBaseClass())
|
|
|
|
TypePtr = TypePtr.getBase();
|
|
|
|
|
|
|
|
QualType DynamicType = TypePtr.getType();
|
|
|
|
if (DynamicType->isPointerType() || DynamicType->isReferenceType())
|
|
|
|
DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
|
|
|
|
else
|
|
|
|
DynamicDecl = DynamicType->getAsCXXRecordDecl();
|
|
|
|
}
|
|
|
|
assert(DynamicDecl);
|
|
|
|
|
2023-01-26 16:25:52 +01:00
|
|
|
const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
|
|
|
|
const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
|
|
|
|
const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
|
|
|
|
DynamicDecl, StaticDecl, InitialFunction);
|
|
|
|
|
|
|
|
if (Overrider != InitialFunction) {
|
2023-08-10 16:04:28 +02:00
|
|
|
// DR1872: An instantiated virtual constexpr function can't be called in a
|
|
|
|
// constant expression (prior to C++20). We can still constant-fold such a
|
|
|
|
// call.
|
|
|
|
if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
|
|
|
|
}
|
|
|
|
|
|
|
|
Func = S.getContext().getOrCreateFunction(Overrider);
|
2023-01-26 16:25:52 +01:00
|
|
|
|
|
|
|
const CXXRecordDecl *ThisFieldDecl =
|
|
|
|
ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
|
|
|
|
if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
|
|
|
|
// If the function we call is further DOWN the hierarchy than the
|
2024-08-11 10:09:03 +02:00
|
|
|
// FieldDesc of our pointer, just go up the hierarchy of this field
|
|
|
|
// the furthest we can go.
|
|
|
|
while (ThisPtr.isBaseClass())
|
|
|
|
ThisPtr = ThisPtr.getBase();
|
2023-01-26 16:25:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-31 09:47:45 +02:00
|
|
|
if (!Call(S, OpPC, Func, VarArgSize))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Covariant return types. The return type of Overrider is a pointer
|
|
|
|
// or reference to a class type.
|
|
|
|
if (Overrider != InitialFunction &&
|
|
|
|
Overrider->getReturnType()->isPointerOrReferenceType() &&
|
|
|
|
InitialFunction->getReturnType()->isPointerOrReferenceType()) {
|
|
|
|
QualType OverriderPointeeType =
|
|
|
|
Overrider->getReturnType()->getPointeeType();
|
|
|
|
QualType InitialPointeeType =
|
|
|
|
InitialFunction->getReturnType()->getPointeeType();
|
|
|
|
// We've called Overrider above, but calling code expects us to return what
|
|
|
|
// InitialFunction returned. According to the rules for covariant return
|
|
|
|
// types, what InitialFunction returns needs to be a base class of what
|
|
|
|
// Overrider returns. So, we need to do an upcast here.
|
|
|
|
unsigned Offset = S.getContext().collectBaseOffset(
|
|
|
|
InitialPointeeType->getAsRecordDecl(),
|
|
|
|
OverriderPointeeType->getAsRecordDecl());
|
|
|
|
return GetPtrBasePop(S, OpPC, Offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2023-01-26 16:25:52 +01:00
|
|
|
}
|
|
|
|
|
2023-07-18 07:47:20 +02:00
|
|
|
inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
|
|
|
|
const CallExpr *CE) {
|
2022-11-05 13:08:40 +01:00
|
|
|
auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
|
|
|
|
|
|
|
|
InterpFrame *FrameBefore = S.Current;
|
|
|
|
S.Current = NewFrame.get();
|
|
|
|
|
2023-07-18 07:47:20 +02:00
|
|
|
if (InterpretBuiltin(S, PC, Func, CE)) {
|
2022-11-05 13:08:40 +01:00
|
|
|
NewFrame.release();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
S.Current = FrameBefore;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-02-25 14:03:47 +01:00
|
|
|
inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
|
|
|
|
const CallExpr *CE) {
|
2023-01-11 12:12:52 +01:00
|
|
|
const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
|
|
|
|
|
|
|
|
const Function *F = FuncPtr.getFunction();
|
2024-02-25 13:50:38 +01:00
|
|
|
if (!F) {
|
2024-08-15 13:18:33 +02:00
|
|
|
const auto *E = cast<CallExpr>(S.Current->getExpr(OpPC));
|
2024-02-25 13:50:38 +01:00
|
|
|
S.FFDiag(E, diag::note_constexpr_null_callee)
|
2024-08-15 13:18:33 +02:00
|
|
|
<< const_cast<Expr *>(E->getCallee()) << E->getSourceRange();
|
2024-02-25 13:50:38 +01:00
|
|
|
return false;
|
|
|
|
}
|
2024-04-15 14:17:31 +02:00
|
|
|
|
2024-08-20 06:08:53 +02:00
|
|
|
if (!FuncPtr.isValid() || !F->getDecl())
|
2024-08-07 13:43:58 +02:00
|
|
|
return Invalid(S, OpPC);
|
2024-04-15 14:17:31 +02:00
|
|
|
|
2024-02-15 06:47:47 +01:00
|
|
|
assert(F);
|
2023-01-11 12:12:52 +01:00
|
|
|
|
2024-07-09 16:02:52 +02:00
|
|
|
// This happens when the call expression has been cast to
|
|
|
|
// something else, but we don't support that.
|
|
|
|
if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
|
|
|
|
S.Ctx.classify(CE->getType()))
|
|
|
|
return false;
|
|
|
|
|
2024-02-25 14:03:47 +01:00
|
|
|
// Check argument nullability state.
|
|
|
|
if (F->hasNonNullAttr()) {
|
|
|
|
if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-02-14 15:29:47 +01:00
|
|
|
assert(ArgSize >= F->getWrittenArgSize());
|
|
|
|
uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
|
|
|
|
|
2024-06-15 07:34:47 +02:00
|
|
|
// We need to do this explicitly here since we don't have the necessary
|
|
|
|
// information to do it automatically.
|
|
|
|
if (F->isThisPointerExplicit())
|
|
|
|
VarArgSize -= align(primSize(PT_Ptr));
|
|
|
|
|
2023-02-16 08:37:03 +01:00
|
|
|
if (F->isVirtual())
|
2024-02-14 15:29:47 +01:00
|
|
|
return CallVirt(S, OpPC, F, VarArgSize);
|
2023-02-16 08:37:03 +01:00
|
|
|
|
2024-02-14 15:29:47 +01:00
|
|
|
return Call(S, OpPC, F, VarArgSize);
|
2023-01-11 12:12:52 +01:00
|
|
|
}
|
|
|
|
|
2023-05-11 14:44:39 +02:00
|
|
|
inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
|
2023-01-11 12:12:52 +01:00
|
|
|
assert(Func);
|
|
|
|
S.Stk.push<FunctionPointer>(Func);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-10 12:53:54 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
|
|
|
|
const T &IntVal = S.Stk.pop<T>();
|
|
|
|
|
|
|
|
S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-06-06 11:17:48 +02:00
|
|
|
inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {
|
|
|
|
S.Stk.push<MemberPointer>(D);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
|
|
|
|
const auto &MP = S.Stk.pop<MemberPointer>();
|
|
|
|
|
|
|
|
S.Stk.push<Pointer>(MP.getBase());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
|
|
|
|
const auto &MP = S.Stk.pop<MemberPointer>();
|
|
|
|
|
|
|
|
const auto *FD = cast<FunctionDecl>(MP.getDecl());
|
|
|
|
const auto *Func = S.getContext().getOrCreateFunction(FD);
|
|
|
|
|
|
|
|
S.Stk.push<FunctionPointer>(Func);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-05-11 16:01:54 +02:00
|
|
|
/// Just emit a diagnostic. The expression that caused emission of this
|
|
|
|
/// op is not valid in a constant context.
|
|
|
|
inline bool Invalid(InterpState &S, CodePtr OpPC) {
|
|
|
|
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
2023-05-12 09:20:33 +02:00
|
|
|
S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
|
|
|
|
<< S.Current->getRange(OpPC);
|
2024-07-02 08:48:23 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool Unsupported(InterpState &S, CodePtr OpPC) {
|
|
|
|
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
|
|
|
|
<< S.Current->getRange(OpPC);
|
2023-05-11 16:01:54 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-03-15 10:34:18 +01:00
|
|
|
/// Do nothing and just abort execution.
|
|
|
|
inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
|
|
|
|
|
2023-06-19 16:24:52 +02:00
|
|
|
/// Same here, but only for casts.
|
2024-08-05 08:17:18 +02:00
|
|
|
inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
|
|
|
|
bool Fatal) {
|
2023-06-19 16:24:52 +02:00
|
|
|
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
2024-02-05 15:28:41 +01:00
|
|
|
|
|
|
|
// FIXME: Support diagnosing other invalid cast kinds.
|
2024-08-05 08:17:18 +02:00
|
|
|
if (Kind == CastKind::Reinterpret) {
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
|
2024-02-05 15:28:41 +01:00
|
|
|
<< static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
|
2024-08-05 08:17:18 +02:00
|
|
|
return !Fatal;
|
|
|
|
}
|
2023-06-19 16:24:52 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-07-28 08:37:41 +02:00
|
|
|
inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
|
|
|
|
const DeclRefExpr *DR) {
|
|
|
|
assert(DR);
|
|
|
|
return CheckDeclRef(S, OpPC, DR);
|
|
|
|
}
|
|
|
|
|
2024-07-22 15:37:17 +08:00
|
|
|
inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
|
|
|
|
if (S.inConstantContext()) {
|
|
|
|
const SourceRange &ArgRange = S.Current->getRange(OpPC);
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-04-22 15:27:15 +02:00
|
|
|
inline bool Assume(InterpState &S, CodePtr OpPC) {
|
|
|
|
const auto Val = S.Stk.pop<Boolean>();
|
|
|
|
|
|
|
|
if (Val)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Else, diagnose.
|
|
|
|
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-07-27 08:30:59 +02:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
|
|
|
|
llvm::SmallVector<int64_t> ArrayIndices;
|
|
|
|
for (size_t I = 0; I != E->getNumExpressions(); ++I)
|
|
|
|
ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
|
|
|
|
|
|
|
|
int64_t Result;
|
|
|
|
if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
S.Stk.push<T>(T::from(Result));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-02-25 14:03:47 +01:00
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
|
|
|
|
const T &Arg = S.Stk.peek<T>();
|
|
|
|
if (!Arg.isZero())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const SourceLocation &Loc = S.Current->getLocation(OpPC);
|
|
|
|
S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-07-18 14:40:55 +02:00
|
|
|
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
|
|
|
|
const APSInt &Value);
|
|
|
|
|
|
|
|
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
|
|
|
inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
|
|
|
|
assert(ED);
|
|
|
|
assert(!ED->isFixed());
|
|
|
|
const APSInt Val = S.Stk.peek<T>().toAPSInt();
|
|
|
|
|
|
|
|
if (S.inConstantContext())
|
|
|
|
diagnoseEnumValue(S, OpPC, ED, Val);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-10 12:53:54 +02:00
|
|
|
/// OldPtr -> Integer -> NewPtr.
|
|
|
|
template <PrimType TIn, PrimType TOut>
|
|
|
|
inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
|
|
|
|
static_assert(isPtrType(TIn) && isPtrType(TOut));
|
|
|
|
using FromT = typename PrimConv<TIn>::T;
|
|
|
|
using ToT = typename PrimConv<TOut>::T;
|
|
|
|
|
|
|
|
const FromT &OldPtr = S.Stk.pop<FromT>();
|
2024-07-23 09:57:31 +02:00
|
|
|
|
|
|
|
if constexpr (std::is_same_v<FromT, FunctionPointer> &&
|
|
|
|
std::is_same_v<ToT, Pointer>) {
|
|
|
|
S.Stk.push<Pointer>(OldPtr.getFunction());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-10 12:53:54 +02:00
|
|
|
S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-07-01 09:12:36 +02:00
|
|
|
inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
|
|
|
|
// An expression E is a core constant expression unless the evaluation of E
|
|
|
|
// would evaluate one of the following: [C++23] - a control flow that passes
|
|
|
|
// through a declaration of a variable with static or thread storage duration
|
|
|
|
// unless that variable is usable in constant expressions.
|
|
|
|
assert(VD->isLocalVarDecl() &&
|
|
|
|
VD->isStaticLocal()); // Checked before emitting this.
|
|
|
|
|
|
|
|
if (VD == S.EvaluatingDecl)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!VD->isUsableInConstantExpressions(S.getCtx())) {
|
|
|
|
S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
|
|
|
|
<< (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-07-15 13:19:33 +02:00
|
|
|
inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
|
|
|
|
assert(Desc);
|
|
|
|
|
|
|
|
if (!CheckDynamicMemoryAllocation(S, OpPC))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
DynamicAllocator &Allocator = S.getAllocator();
|
|
|
|
Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID());
|
|
|
|
assert(B);
|
|
|
|
|
|
|
|
S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
|
|
|
|
inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
|
|
|
|
bool IsNoThrow) {
|
|
|
|
if (!CheckDynamicMemoryAllocation(S, OpPC))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SizeT NumElements = S.Stk.pop<SizeT>();
|
|
|
|
if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
|
|
|
|
if (!IsNoThrow)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If this failed and is nothrow, just return a null ptr.
|
|
|
|
S.Stk.push<Pointer>(0, nullptr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
DynamicAllocator &Allocator = S.getAllocator();
|
|
|
|
Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
|
|
|
|
S.Ctx.getEvalID());
|
|
|
|
assert(B);
|
|
|
|
S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
|
|
|
|
inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
|
|
|
|
bool IsNoThrow) {
|
|
|
|
if (!CheckDynamicMemoryAllocation(S, OpPC))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SizeT NumElements = S.Stk.pop<SizeT>();
|
|
|
|
if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
|
|
|
|
IsNoThrow)) {
|
|
|
|
if (!IsNoThrow)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If this failed and is nothrow, just return a null ptr.
|
|
|
|
S.Stk.push<Pointer>(0, ElementDesc);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
DynamicAllocator &Allocator = S.getAllocator();
|
|
|
|
Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
|
|
|
|
S.Ctx.getEvalID());
|
|
|
|
assert(B);
|
|
|
|
|
|
|
|
S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-07-18 07:11:00 +02:00
|
|
|
bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B);
|
2024-07-15 13:19:33 +02:00
|
|
|
static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
|
|
|
|
if (!CheckDynamicMemoryAllocation(S, OpPC))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const Expr *Source = nullptr;
|
|
|
|
const Block *BlockToDelete = nullptr;
|
|
|
|
{
|
|
|
|
// Extra scope for this so the block doesn't have this pointer
|
|
|
|
// pointing to it when we destroy it.
|
|
|
|
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
|
|
|
|
|
|
|
// Deleteing nullptr is always fine.
|
|
|
|
if (Ptr.isZero())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
|
|
|
|
<< Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Source = Ptr.getDeclDesc()->asExpr();
|
|
|
|
BlockToDelete = Ptr.block();
|
|
|
|
|
|
|
|
if (!CheckDeleteSource(S, OpPC, Source, Ptr))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
assert(Source);
|
|
|
|
assert(BlockToDelete);
|
|
|
|
|
2024-07-18 07:11:00 +02:00
|
|
|
// Invoke destructors before deallocating the memory.
|
|
|
|
if (!RunDestructors(S, OpPC, BlockToDelete))
|
|
|
|
return false;
|
|
|
|
|
2024-07-15 13:19:33 +02:00
|
|
|
DynamicAllocator &Allocator = S.getAllocator();
|
|
|
|
bool WasArrayAlloc = Allocator.isArrayAllocation(Source);
|
|
|
|
const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
|
|
|
|
|
|
|
|
if (!Allocator.deallocate(Source, BlockToDelete, S)) {
|
|
|
|
// Nothing has been deallocated, this must be a double-delete.
|
|
|
|
const SourceInfo &Loc = S.Current->getSource(OpPC);
|
|
|
|
S.FFDiag(Loc, diag::note_constexpr_double_delete);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm,
|
|
|
|
BlockDesc, Source);
|
|
|
|
}
|
|
|
|
|
2024-07-22 16:35:21 +02:00
|
|
|
inline bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
|
|
|
|
assert(T);
|
|
|
|
assert(!S.getLangOpts().CPlusPlus23);
|
|
|
|
|
|
|
|
// C++1y: A constant initializer for an object o [...] may also invoke
|
|
|
|
// constexpr constructors for o and its subobjects even if those objects
|
|
|
|
// are of non-literal class types.
|
|
|
|
//
|
|
|
|
// C++11 missed this detail for aggregates, so classes like this:
|
|
|
|
// struct foo_t { union { int i; volatile int j; } u; };
|
|
|
|
// are not (obviously) initializable like so:
|
|
|
|
// __attribute__((__require_constant_initialization__))
|
|
|
|
// static const foo_t x = {{0}};
|
|
|
|
// because "i" is a subobject with non-literal initialization (due to the
|
|
|
|
// volatile member of the union). See:
|
|
|
|
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
|
|
|
|
// Therefore, we use the C++1y behavior.
|
|
|
|
|
|
|
|
if (S.EvaluatingDecl)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&
|
|
|
|
S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const Expr *E = S.Current->getExpr(OpPC);
|
|
|
|
if (S.getLangOpts().CPlusPlus11)
|
|
|
|
S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
|
|
|
|
else
|
|
|
|
S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
[Clang interpreter] Avoid storing pointers at unaligned locations
The Clang interpreter's bytecode uses a packed stream of bytes
representation, but also wants to have some opcodes take pointers as
arguments, which are currently embedded in the bytecode directly.
However, CHERI, and thus Arm's upcoming experimental Morello prototype,
provide spatial memory safety for C/C++ by implementing language-level
(and sub-language-level) pointers as capabilities, which track bounds,
permissions and validity in hardware. This uses tagged memory with a
single tag bit at every capability-aligned address, and so storing
pointers to unaligned addresses results in the tag being stripped,
leading to a tag fault when the pointer is ultimately dereferenced at a
later point.
In order to support a stricter C/C++ implementation like CHERI, we no
longer store pointers directly in the bytecode, instead storing them in
a table and embedding the index in the bytecode.
Reviewed By: nand
Differential Revision: https://reviews.llvm.org/D97606
2021-07-28 14:49:37 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Read opcode arguments
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-09-17 16:14:37 +02:00
|
|
|
template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
|
|
|
|
if constexpr (std::is_pointer<T>::value) {
|
|
|
|
uint32_t ID = OpPC.read<uint32_t>();
|
|
|
|
return reinterpret_cast<T>(S.P.getNativePointer(ID));
|
|
|
|
} else {
|
|
|
|
return OpPC.read<T>();
|
|
|
|
}
|
[Clang interpreter] Avoid storing pointers at unaligned locations
The Clang interpreter's bytecode uses a packed stream of bytes
representation, but also wants to have some opcodes take pointers as
arguments, which are currently embedded in the bytecode directly.
However, CHERI, and thus Arm's upcoming experimental Morello prototype,
provide spatial memory safety for C/C++ by implementing language-level
(and sub-language-level) pointers as capabilities, which track bounds,
permissions and validity in hardware. This uses tagged memory with a
single tag bit at every capability-aligned address, and so storing
pointers to unaligned addresses results in the tag being stripped,
leading to a tag fault when the pointer is ultimately dereferenced at a
later point.
In order to support a stricter C/C++ implementation like CHERI, we no
longer store pointers directly in the bytecode, instead storing them in
a table and embedding the index in the bytecode.
Reviewed By: nand
Differential Revision: https://reviews.llvm.org/D97606
2021-07-28 14:49:37 +01:00
|
|
|
}
|
|
|
|
|
2023-07-13 11:17:56 +02:00
|
|
|
template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
|
|
|
|
Floating F = Floating::deserialize(*OpPC);
|
|
|
|
OpPC += align(F.bytesToSerialize());
|
|
|
|
return F;
|
|
|
|
}
|
|
|
|
|
2024-01-31 10:00:42 +01:00
|
|
|
template <>
|
|
|
|
inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
|
|
|
|
CodePtr &OpPC) {
|
|
|
|
IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
|
|
|
|
OpPC += align(I.bytesToSerialize());
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
|
|
|
|
CodePtr &OpPC) {
|
|
|
|
IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
|
|
|
|
OpPC += align(I.bytesToSerialize());
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
} // namespace interp
|
|
|
|
} // namespace clang
|
|
|
|
|
|
|
|
#endif
|