[clang][Interp] Handle sizeof()

Implement visiting UnaryExprOrTypeTraitExprs to handle sizeof()
expressions.

Differential Revision: https://reviews.llvm.org/D133934
This commit is contained in:
Timm Bäder
2022-09-14 16:53:55 +02:00
parent 1c35f3b93a
commit ee2e414d66
5 changed files with 99 additions and 6 deletions

View File

@@ -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; }

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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
};