mirror of
https://github.com/intel/llvm.git
synced 2026-02-02 18:18:09 +08:00
[clang][Interp] Handle sizeof()
Implement visiting UnaryExprOrTypeTraitExprs to handle sizeof() expressions. Differential Revision: https://reviews.llvm.org/D133934
This commit is contained in:
@@ -47,6 +47,10 @@ class Boolean {
|
||||
Boolean operator~() const { return Boolean(true); }
|
||||
|
||||
explicit operator unsigned() const { return V; }
|
||||
explicit operator int8_t() const { return V; }
|
||||
explicit operator uint8_t() const { return V; }
|
||||
explicit operator int16_t() const { return V; }
|
||||
explicit operator uint16_t() const { return V; }
|
||||
explicit operator int64_t() const { return V; }
|
||||
explicit operator uint64_t() const { return V; }
|
||||
explicit operator int() const { return V; }
|
||||
|
||||
@@ -281,7 +281,29 @@ bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) {
|
||||
}
|
||||
|
||||
template <class Emitter>
|
||||
bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
|
||||
bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
|
||||
const UnaryExprOrTypeTraitExpr *E) {
|
||||
|
||||
if (E->getKind() == UETT_SizeOf) {
|
||||
QualType ArgType = E->getTypeOfArgument();
|
||||
|
||||
CharUnits Size;
|
||||
if (ArgType->isVoidType() || ArgType->isFunctionType())
|
||||
Size = CharUnits::One();
|
||||
else {
|
||||
if (ArgType->isDependentType() || !ArgType->isConstantSizeType())
|
||||
return false;
|
||||
|
||||
Size = Ctx.getASTContext().getTypeSizeInChars(ArgType);
|
||||
}
|
||||
|
||||
return this->emitConst(E, Size.getQuantity());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
|
||||
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
|
||||
return this->Visit(E);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ public:
|
||||
bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
|
||||
bool VisitInitListExpr(const InitListExpr *E);
|
||||
bool VisitConstantExpr(const ConstantExpr *E);
|
||||
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
|
||||
|
||||
protected:
|
||||
bool visitExpr(const Expr *E) override;
|
||||
|
||||
@@ -427,11 +427,11 @@ def Neg: Opcode {
|
||||
// TODO: Expand this to handle casts between more types.
|
||||
|
||||
def FromCastTypeClass : TypeClass {
|
||||
let Types = [Uint32, Sint32, Bool];
|
||||
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
|
||||
}
|
||||
|
||||
def ToCastTypeClass : TypeClass {
|
||||
let Types = [Uint32, Sint32, Bool];
|
||||
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
|
||||
}
|
||||
|
||||
def Cast: Opcode {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++11 -verify %s
|
||||
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
|
||||
// RUN: %clang_cc1 -std=c++11 -verify=ref %s
|
||||
// RUN: %clang_cc1 -std=c++20 -verify=ref %s
|
||||
|
||||
static_assert(true, "");
|
||||
static_assert(false, ""); // expected-error{{failed}} ref-error{{failed}}
|
||||
@@ -72,10 +74,74 @@ static_assert(*p == 10, "");
|
||||
constexpr const int* getIntPointer() {
|
||||
return &m;
|
||||
}
|
||||
//static_assert(getIntPointer() == &m, ""); TODO
|
||||
//static_assert(*getIntPointer() == 10, ""); TODO
|
||||
static_assert(getIntPointer() == &m, "");
|
||||
static_assert(*getIntPointer() == 10, "");
|
||||
|
||||
constexpr int gimme(int k) {
|
||||
return k;
|
||||
}
|
||||
// static_assert(gimme(5) == 5, ""); TODO
|
||||
static_assert(gimme(5) == 5, "");
|
||||
|
||||
namespace SizeOf {
|
||||
constexpr int soint = sizeof(int);
|
||||
constexpr int souint = sizeof(unsigned int);
|
||||
static_assert(soint == souint, "");
|
||||
|
||||
static_assert(sizeof(&soint) == sizeof(void*), "");
|
||||
static_assert(sizeof(&soint) == sizeof(nullptr), "");
|
||||
|
||||
static_assert(sizeof(long) == sizeof(unsigned long), "");
|
||||
static_assert(sizeof(char) == sizeof(unsigned char), "");
|
||||
|
||||
constexpr int N = 4;
|
||||
constexpr int arr[N] = {1,2,3,4};
|
||||
static_assert(sizeof(arr) == N * sizeof(int), "");
|
||||
static_assert(sizeof(arr) == N * sizeof(arr[0]), "");
|
||||
|
||||
constexpr bool arrB[N] = {true, true, true, true};
|
||||
static_assert(sizeof(arrB) == N * sizeof(bool), "");
|
||||
|
||||
static_assert(sizeof(bool) == 1, "");
|
||||
static_assert(sizeof(char) == 1, "");
|
||||
|
||||
constexpr int F = sizeof(void); // expected-error{{incomplete type 'void'}} \
|
||||
// ref-error{{incomplete type 'void'}}
|
||||
|
||||
constexpr int F2 = sizeof(gimme); // expected-error{{to a function type}} \
|
||||
// ref-error{{to a function type}}
|
||||
|
||||
|
||||
|
||||
/// FIXME: The following code should be accepted.
|
||||
struct S {
|
||||
void func();
|
||||
};
|
||||
constexpr void (S::*Func)() = &S::func; // expected-error {{must be initialized by a constant expression}} \
|
||||
// expected-error {{interpreter failed to evaluate an expression}}
|
||||
static_assert(sizeof(Func) == sizeof(&S::func), "");
|
||||
|
||||
|
||||
void func() {
|
||||
int n = 12;
|
||||
constexpr int oofda = sizeof(int[n++]); // expected-error {{must be initialized by a constant expression}} \
|
||||
// ref-error {{must be initialized by a constant expression}}
|
||||
}
|
||||
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
/// FIXME: The following code should be accepted.
|
||||
consteval int foo(int n) { // ref-error {{consteval function never produces a constant expression}}
|
||||
return sizeof(int[n]); // ref-note 3{{not valid in a constant expression}} \
|
||||
// expected-note {{not valid in a constant expression}}
|
||||
}
|
||||
constinit int var = foo(5); // ref-error {{not a constant expression}} \
|
||||
// ref-note 2{{in call to}} \
|
||||
// ref-error {{does not have a constant initializer}} \
|
||||
// ref-note {{required by 'constinit' specifier}} \
|
||||
// expected-error {{is not a constant expression}} \
|
||||
// expected-note {{in call to}} \
|
||||
// expected-error {{does not have a constant initializer}} \
|
||||
// expected-note {{required by 'constinit' specifier}} \
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user