ayzhao created this revision.
Herald added a project: All.
ayzhao requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

- Fix an issue where temporaries initialized via parenthesized aggregate 
initialization don't get destroyed.
- Fix an issue where aggregate initialization omits calls to class members' 
move constructors after a TreeTransform. This occurs because the 
CXXConstructExpr wrapping the call to the move constructor gets unboxed during 
a TreeTransform of the wrapping FunctionalCastExpr (as with a InitListExpr), 
but unlike InitListExpr, we dont reperform the InitializationSequence for the 
list's expressions to regenerate the CXXConstructExpr. This patch fixes this 
bug by treating CXXParenListInitExpr identically to InitListExpr in this regard.

Fixes #61145


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D146465

Files:
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/test/CodeGen/paren-list-agg-init.cpp

Index: clang/test/CodeGen/paren-list-agg-init.cpp
===================================================================
--- clang/test/CodeGen/paren-list-agg-init.cpp
+++ clang/test/CodeGen/paren-list-agg-init.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++20 %s -Wno-unused-value -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
 
 template <typename T>
 struct IsChar {
@@ -69,6 +69,22 @@
   char b;
 };
 
+
+namespace gh61145 {
+  // CHECK-DAG: [[STRUCT_VEC:%.*]] = type { i8 }
+  struct Vec {
+    Vec();
+    Vec(Vec&&);
+    ~Vec();
+  };
+
+  // CHECK-DAG: [[STRUCT_S:%.*]] = type { [[STRUCT_VEC]] }
+  struct S {
+    Vec v;
+  };
+
+}
+
 // CHECK-DAG: [[A1:@.*a1.*]] = internal constant [[STRUCT_A]] { i8 3, double 2.000000e+00 }, align 8
 constexpr A a1(3.1, 2.0);
 // CHECK-DAG: [[A2:@.*a2.*]] = internal constant [[STRUCT_A]] { i8 99, double 0.000000e+00 }, align 8
@@ -349,3 +365,30 @@
 void foo19() {
   G g(2);
 }
+
+namespace gh61145 {
+  // a.k.a. void make<1>()
+  // CHECK: define {{.*}} void @_ZN7gh611454makeILi0EEEvv
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: [[V:%.*v.*]] = alloca [[STRUCT_VEC]], align 1
+  // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S]], align 1
+  // CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+  // a.k.a. Vec::Vec()
+  // CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
+  // a.k.a. Vec::Vec(Vec&&)
+  // CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+  // a.k.a. S::~S();
+  // CHECK-NEXT: call void @_ZN7gh611451SD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]]
+  // a.k.a.Vec::~Vec()
+  // CHECK-NEXT: call void @_ZN7gh611453VecD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+  // CHECK-NEXT: ret void
+  template <int I>
+  void make() {
+    Vec v;
+    S((Vec&&) v);
+  }
+
+  void foo() {
+    make<0>();
+  }
+}
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -9180,6 +9180,8 @@
                                         /*VerifyOnly=*/false, &CurInit);
       if (CurInit.get() && ResultType)
         *ResultType = CurInit.get()->getType();
+      if (shouldBindAsTemporary(Entity))
+        CurInit = S.MaybeBindToTemporary(CurInit.get());
       break;
     }
     }
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -1548,7 +1548,7 @@
   // conversion expression is equivalent (in definedness, and if defined in
   // meaning) to the corresponding cast expression.
   if (Exprs.size() == 1 && !ListInitialization &&
-      !isa<InitListExpr>(Exprs[0])) {
+      !isa<InitListExpr>(Exprs[0]) && !isa<CXXParenListInitExpr>(Exprs[0])) {
     Expr *Arg = Exprs[0];
     return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenOrBraceLoc, Arg,
                                       RParenOrBraceLoc);
@@ -1579,10 +1579,28 @@
                           diag::err_invalid_incomplete_type_use, FullRange))
     return ExprError();
 
-  //   Otherwise, the expression is a prvalue of the specified type whose
-  //   result object is direct-initialized (11.6) with the initializer.
-  InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
-  ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs);
+  MultiExprArg ExprsToPass;
+  if (Exprs.size() == 1 && isa<CXXParenListInitExpr>(Exprs[0])) {
+    // C++20 [expr.static.cast]p4:
+    //   An expression E can be explicitly converted to a type T...if T is an
+    //   aggregate type ([dcl.init.aggr]) having a first element x and there is
+    //   an implicit conversion sequence from E to the type of x
+    //
+    // Unlike for InitListExprs, InitializationSequence(..) doesn't take the
+    // overall CXXParenListInitExpr as the first element, so we instead pass
+    // it the elements of the CXXParenListInitExpr and have it deduce the
+    // initialization type and generate a new CXXParenListInitExpr.
+    auto *CPLIE = cast<CXXParenListInitExpr>(Exprs[0]);
+    ExprsToPass =
+        MultiExprArg(const_cast<Expr **>(CPLIE->getInitExprs().begin()),
+                     CPLIE->getInitExprs().size());
+  } else {
+    //   Otherwise, the expression is a prvalue of the specified type whose
+    //   result object is direct-initialized (11.6) with the initializer.
+    ExprsToPass = Exprs;
+  }
+  InitializationSequence InitSeq(*this, Entity, Kind, ExprsToPass);
+  ExprResult Result = InitSeq.Perform(*this, Entity, Kind, ExprsToPass);
 
   if (Result.isInvalid())
     return Result;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to