[clang] ee2e414 - [clang][Interp] Handle sizeof()

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 29 03:51:26 PDT 2022


Author: Timm Bäder
Date: 2022-09-29T12:50:55+02:00
New Revision: ee2e414d66a4b3b4e1a3bade11168a108f349d8a

URL: https://github.com/llvm/llvm-project/commit/ee2e414d66a4b3b4e1a3bade11168a108f349d8a
DIFF: https://github.com/llvm/llvm-project/commit/ee2e414d66a4b3b4e1a3bade11168a108f349d8a.diff

LOG: [clang][Interp] Handle sizeof()

Implement visiting UnaryExprOrTypeTraitExprs to handle sizeof()
expressions.

Differential Revision: https://reviews.llvm.org/D133934

Added: 
    

Modified: 
    clang/lib/AST/Interp/Boolean.h
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/Opcodes.td
    clang/test/AST/Interp/literals.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h
index e739ce28e92c5..f1a0b9007df80 100644
--- a/clang/lib/AST/Interp/Boolean.h
+++ b/clang/lib/AST/Interp/Boolean.h
@@ -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; }

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index f86a7b1aa1898..5974678f0cfc9 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -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);
 }

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 6a74bc371855e..d73a8dfb18c28 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -80,6 +80,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   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;

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 49cc0e0253de6..c743807714b1f 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -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 {

diff  --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 5c1df00a25e77..5de727f005c86 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -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
+};


        


More information about the cfe-commits mailing list