[clang] 33b5283 - [clang][Interp] Fix using default copy constructors

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 14 01:22:24 PDT 2022


Author: Timm Bäder
Date: 2022-10-14T10:21:53+02:00
New Revision: 33b52836de6e093acea15f24b6ae633f969d194a

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

LOG: [clang][Interp] Fix using default copy constructors

Implement ArrayInitLoopExprs, which are used in copy constructors to
copy arrays. Also fix problems encountered while doing that.

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

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/ByteCodeStmtGen.cpp
    clang/test/AST/Interp/records.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 66e373e427c8..b9e7f4e2cdad 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -326,6 +326,18 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
   return false;
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
+    const ArrayInitIndexExpr *E) {
+  assert(ArrayIndex);
+  return this->emitConstUint64(*ArrayIndex, E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+  return this->visit(E->getSourceExpr());
+}
+
 template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
   OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
   return this->Visit(E);
@@ -628,6 +640,32 @@ bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
     return true;
   } else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
     return this->visitInitializer(DIE->getExpr());
+  } else if (const auto *AILE = dyn_cast<ArrayInitLoopExpr>(Initializer)) {
+    // TODO: This compiles to quite a lot of bytecode if the array is larger.
+    //   Investigate compiling this to a loop, or at least try to use
+    //   the AILE's Common expr.
+    const Expr *SubExpr = AILE->getSubExpr();
+    size_t Size = AILE->getArraySize().getZExtValue();
+    Optional<PrimType> ElemT = classify(SubExpr->getType());
+
+    if (!ElemT)
+      return false;
+
+    for (size_t I = 0; I != Size; ++I) {
+      ArrayIndexScope<Emitter> IndexScope(this, I);
+      if (!this->emitDupPtr(SubExpr))
+        return false;
+
+      if (!this->visit(SubExpr))
+        return false;
+
+      if (!this->emitInitElem(*ElemT, I, Initializer))
+        return false;
+
+      if (!this->emitPopPtr(Initializer))
+        return false;
+    }
+    return true;
   }
 
   assert(false && "Unknown expression for array initialization");
@@ -642,13 +680,20 @@ bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
   if (const auto CtorExpr = dyn_cast<CXXConstructExpr>(Initializer)) {
     const Function *Func = getFunction(CtorExpr->getConstructor());
 
-    if (!Func)
+    if (!Func || !Func->isConstexpr())
       return false;
 
     // The This pointer is already on the stack because this is an initializer,
     // but we need to dup() so the call() below has its own copy.
     if (!this->emitDupPtr(Initializer))
       return false;
+
+    // Constructor arguments.
+    for (const auto *Arg : CtorExpr->arguments()) {
+      if (!this->visit(Arg))
+        return false;
+    }
+
     return this->emitCallVoid(Func, Initializer);
   } else if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
     const Record *R = getRecord(InitList->getType());
@@ -657,15 +702,26 @@ bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
     for (const Expr *Init : InitList->inits()) {
       const Record::Field *FieldToInit = R->getField(InitIndex);
 
-      if (Optional<PrimType> T = classify(Init->getType())) {
-        if (!this->emitDupPtr(Initializer))
-          return false;
+      if (!this->emitDupPtr(Initializer))
+        return false;
 
+      if (Optional<PrimType> T = classify(Init->getType())) {
         if (!this->visit(Init))
           return false;
 
         if (!this->emitInitField(*T, FieldToInit->Offset, Initializer))
           return false;
+      } else {
+        // Non-primitive case. Get a pointer to the field-to-initialize
+        // on the stack and recurse into visitInitializer().
+        if (!this->emitGetPtrField(FieldToInit->Offset, Init))
+          return false;
+
+        if (!this->visitInitializer(Init))
+          return false;
+
+        if (!this->emitPopPtr(Initializer))
+          return false;
       }
       ++InitIndex;
     }

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 14356ec9cdee..32ff72aa36fb 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -34,6 +34,7 @@ template <class Emitter> class RecordScope;
 template <class Emitter> class VariableScope;
 template <class Emitter> class DeclScope;
 template <class Emitter> class OptionScope;
+template <class Emitter> class ArrayIndexScope;
 
 /// Compilation context for expressions.
 template <class Emitter>
@@ -85,6 +86,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool VisitConstantExpr(const ConstantExpr *E);
   bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
   bool VisitMemberExpr(const MemberExpr *E);
+  bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
+  bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
@@ -199,6 +202,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   friend class RecordScope<Emitter>;
   friend class DeclScope<Emitter>;
   friend class OptionScope<Emitter>;
+  friend class ArrayIndexScope<Emitter>;
 
   /// Emits a zero initializer.
   bool visitZeroInitializer(PrimType T, const Expr *E);
@@ -260,7 +264,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   /// Current scope.
   VariableScope<Emitter> *VarScope = nullptr;
 
-  /// Current argument index.
+  /// Current argument index. Needed to emit ArrayInitIndexExpr.
   llvm::Optional<uint64_t> ArrayIndex;
 
   /// Flag indicating if return value is to be discarded.
@@ -362,6 +366,20 @@ template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
   }
 };
 
+template <class Emitter> class ArrayIndexScope final {
+public:
+  ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
+    OldArrayIndex = Ctx->ArrayIndex;
+    Ctx->ArrayIndex = Index;
+  }
+
+  ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
+
+private:
+  ByteCodeExprGen<Emitter> *Ctx;
+  Optional<uint64_t> OldArrayIndex;
+};
+
 } // namespace interp
 } // namespace clang
 

diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index b4a61ebed0e7..3aa659822bb8 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -105,7 +105,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
       const Record::Field *F = R->getField(Member);
 
       if (Optional<PrimType> T = this->classify(InitExpr->getType())) {
-        if (!this->emitDupPtr(InitExpr))
+        if (!this->emitThis(InitExpr))
           return false;
 
         if (!this->visit(InitExpr))
@@ -116,7 +116,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
       } else {
         // Non-primitive case. Get a pointer to the field-to-initialize
         // on the stack and call visitInitialzer() for it.
-        if (!this->emitDupPtr(InitExpr))
+        if (!this->emitThis(InitExpr))
           return false;
 
         if (!this->emitGetPtrField(F->Offset, InitExpr))

diff  --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 8d62b53d622a..1e61d4845a43 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -32,6 +32,9 @@ static_assert(ints.a == 20, "");
 static_assert(ints.b == 30, "");
 static_assert(ints.c, "");
 static_assert(ints.getTen() == 10, "");
+static_assert(ints.numbers[0] == 1, "");
+static_assert(ints.numbers[1] == 2, "");
+static_assert(ints.numbers[2] == 3, "");
 
 constexpr const BoolPair &BP = ints.bp;
 static_assert(BP.first, "");
@@ -62,11 +65,17 @@ constexpr Ints ints4 = {
 static_assert(ints4.a == (40 * 50), "");
 static_assert(ints4.b == 0, "");
 static_assert(ints4.c, "");
-
-
-// FIXME: Implement initialization by DeclRefExpr.
-//constexpr Ints ints4 = ints3;  TODO
-
+static_assert(ints4.numbers[0] == 1, "");
+static_assert(ints4.numbers[1] == 2, "");
+static_assert(ints4.numbers[2] == 3, "");
+
+constexpr Ints ints5 = ints4;
+static_assert(ints5.a == (40 * 50), "");
+static_assert(ints5.b == 0, "");
+static_assert(ints5.c, "");
+static_assert(ints5.numbers[0] == 1, "");
+static_assert(ints5.numbers[1] == 2, "");
+static_assert(ints5.numbers[2] == 3, "");
 
 
 struct Ints2 {


        


More information about the cfe-commits mailing list