tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Unify `CXXTemporaryObjectExpr` and `CXXConstructExpr` code and zero-initialize 
the object if requested.

Hints on how to test this properly without creating some weird intermediate 
object are welcome of course. :)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154189

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Descriptor.cpp
  clang/lib/AST/Interp/Descriptor.h
  clang/test/AST/Interp/records.cpp

Index: clang/test/AST/Interp/records.cpp
===================================================================
--- clang/test/AST/Interp/records.cpp
+++ clang/test/AST/Interp/records.cpp
@@ -899,3 +899,45 @@
   return bp.first && bp.second;
 }
 static_assert(BPand(BoolPair{true, false}) == false, "");
+
+
+namespace ZeroInit {
+  struct F {
+    int a;
+  };
+
+  namespace Simple {
+    struct A {
+      char a;
+      bool b;
+      int c[4];
+      float d;
+    };
+    constexpr int foo(A x) {
+      return x.a + static_cast<int>(x.b) + x.c[0] + x.c[3] + static_cast<int>(x.d);
+    }
+#if __cplusplus >= 201703L
+    static_assert(foo(A()) == 0, "");
+#endif
+  }
+
+#if __cplusplus >= 202002L
+  namespace Failure {
+    struct S {
+      int a;
+      F f{12};
+    };
+    constexpr int foo(S x) {
+      return x.a; // expected-note {{read of object outside its lifetime}} \
+                  // ref-note {{read of uninitialized object}}
+    }
+    static_assert(foo(S()) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                      // expected-note {{in call to}} \
+                                      // ref-error {{not an integral constant expression}} \
+                                      // ref-note {{in call to}}
+  };
+#endif
+
+
+}
+
Index: clang/lib/AST/Interp/Descriptor.h
===================================================================
--- clang/lib/AST/Interp/Descriptor.h
+++ clang/lib/AST/Interp/Descriptor.h
@@ -137,6 +137,7 @@
              bool IsTemporary, bool IsMutable);
 
   QualType getType() const;
+  QualType getElemQualType() const;
   SourceLocation getLocation() const;
 
   const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
Index: clang/lib/AST/Interp/Descriptor.cpp
===================================================================
--- clang/lib/AST/Interp/Descriptor.cpp
+++ clang/lib/AST/Interp/Descriptor.cpp
@@ -278,6 +278,16 @@
   llvm_unreachable("Invalid descriptor type");
 }
 
+QualType Descriptor::getElemQualType() const {
+  assert(isArray());
+  QualType T = getType();
+
+  const auto *CAT = cast<ConstantArrayType>(T);
+  return CAT->getElementType();
+
+  return T;
+}
+
 SourceLocation Descriptor::getLocation() const {
   if (auto *D = Source.dyn_cast<const Decl *>())
     return D->getLocation();
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -92,7 +92,6 @@
   bool VisitExprWithCleanups(const ExprWithCleanups *E);
   bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
   bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);
-  bool VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *E);
   bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
   bool VisitTypeTraitExpr(const TypeTraitExpr *E);
   bool VisitLambdaExpr(const LambdaExpr *E);
@@ -210,6 +209,7 @@
 
   /// Emits a zero initializer.
   bool visitZeroInitializer(QualType QT, const Expr *E);
+  bool visitZeroRecordInitializer(const Record *R, const Expr *E);
 
   enum class DerefKind {
     /// Value is read and pushed to stack.
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1019,24 +1019,6 @@
   return this->visit(E->getSubExpr());
 }
 
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXTemporaryObjectExpr(
-    const CXXTemporaryObjectExpr *E) {
-  if (std::optional<unsigned> LocalIndex =
-          allocateLocal(E, /*IsExtended=*/false)) {
-    if (!this->emitGetPtrLocal(*LocalIndex, E))
-      return false;
-
-    if (!this->visitInitializer(E))
-      return false;
-
-    if (DiscardResult)
-      return this->emitPopPtr(E);
-    return true;
-  }
-  return false;
-}
-
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr(
     const CompoundLiteralExpr *E) {
@@ -1119,19 +1101,30 @@
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr(
     const CXXConstructExpr *E) {
-  if (std::optional<unsigned> GI = allocateLocal(E, /*IsExtended=*/false)) {
-    if (!this->emitGetPtrLocal(*GI, E))
-      return false;
+  std::optional<unsigned> LocalIndex = allocateLocal(E, /*IsExtended=*/false);
+  if (!LocalIndex)
+    return false;
 
-    if (!this->visitRecordInitializer(E))
-      return false;
+  if (!this->emitGetPtrLocal(*LocalIndex, E))
+    return false;
 
-    if (DiscardResult)
-      return this->emitPopPtr(E);
-    return true;
+  const CXXConstructorDecl *Ctor = E->getConstructor();
+
+  // If zero-init is requested and the constructor is trivial, zero-init
+  // all field and bases explicitly.
+  if (E->requiresZeroInitialization() && Ctor->isTrivial()) {
+    assert(E->getType()->isRecordType());
+    const Record *R = getRecord(E->getType());
+
+    if (!this->visitZeroRecordInitializer(R, E))
+      return false;
+  } else {
+    // Otherwise, just call the constructor.
+    if (!this->visitInitializer(E))
+      return false;
   }
 
-  return false;
+  return DiscardResult ? this->emitPopPtr(E) : true;
 }
 
 template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
@@ -1240,6 +1233,48 @@
   }
   llvm_unreachable("unknown primitive type");
 }
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
+                                                          const Expr *E) {
+  // Fields
+  for (const Record::Field &Field : R->fields()) {
+    const Descriptor *D = Field.Desc;
+    if (D->isPrimitive()) {
+      QualType QT = D->getType();
+      PrimType T = classifyPrim(D->getType());
+      if (!this->visitZeroInitializer(QT, E))
+        return false;
+      if (!this->emitInitField(T, Field.Offset, E))
+        return false;
+      continue;
+    }
+
+    // TODO: Add GetPtrFieldPop and get rid of this dup.
+    if (!this->emitDupPtr(E))
+      return false;
+    if (!this->emitGetPtrField(Field.Offset, E))
+      return false;
+
+    if (D->isPrimitiveArray()) {
+      QualType ET = D->getElemQualType();
+      PrimType T = classifyPrim(ET);
+      for (uint32_t I = 0, N = D->getNumElems(); I != N; ++I) {
+        if (!this->visitZeroInitializer(ET, E))
+          return false;
+        if (!this->emitInitElem(T, I, E))
+          return false;
+      }
+    } else {
+      // FIXME: Implement class and composite array types.
+      assert(false);
+    }
+
+    if (!this->emitPopPtr(E))
+      return false;
+  }
+
+  return true;
+}
 
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::dereference(
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to