[clang] [clang] Fix type of the MaterializeTemporaryExpr with incomplete array type. (PR #187618)

Eli Friedman via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 15 12:47:31 PDT 2026


https://github.com/efriedma-quic updated https://github.com/llvm/llvm-project/pull/187618

>From b44592ea0074a60455826ceb7e96cc66d0a06b27 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at qti.qualcomm.com>
Date: Thu, 19 Mar 2026 17:59:23 -0700
Subject: [PATCH 1/4] Fix type of the MaterializeTemporaryExpr with incomplete
 array type.

This affects constructs like `int f(int (&&x)[]); int z = f({1});`.

A temporary logically can't have incomplete type: if we don't know the
type, we can't materialize it.  Rearrange the casts to make more sense.

I'm not sure this has any practical effects at the moment due to the way
we use skipRValueSubobjectAdjustments; we usually end up ignoring the
type of the MaterializeTemporaryExpr.
---
 clang/lib/Sema/SemaInit.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index e54a25405c816..a41c1f456efe9 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -4979,6 +4979,8 @@ static void TryReferenceListInitialization(Sema &S,
   if (Sequence) {
     if (DestType->isRValueReferenceType() ||
         (T1Quals.hasConst() && !T1Quals.hasVolatile())) {
+      Sequence.AddReferenceBindingStep(cv1T1IgnoreAS,
+                                       /*BindingTemporary=*/true);
       if (S.getLangOpts().CPlusPlus20 &&
           isa<IncompleteArrayType>(T1->getUnqualifiedDesugaredType()) &&
           DestType->isRValueReferenceType()) {
@@ -4988,10 +4990,8 @@ static void TryReferenceListInitialization(Sema &S,
         // ..., unless T is “reference to array of unknown bound of U”, in which
         // case the type of the prvalue is the type of x in the declaration U
         // x[] H, where H is the initializer list.
-        Sequence.AddQualificationConversionStep(cv1T1, clang::VK_PRValue);
+        Sequence.AddQualificationConversionStep(cv1T1, clang::VK_XValue);
       }
-      Sequence.AddReferenceBindingStep(cv1T1IgnoreAS,
-                                       /*BindingTemporary=*/true);
       if (T1Quals.hasAddressSpace())
         Sequence.AddQualificationConversionStep(
             cv1T1, DestType->isRValueReferenceType() ? VK_XValue : VK_LValue);

>From 8b8d85fcb12a3bae8609aacd3c4eb4fe41e2cee0 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at qti.qualcomm.com>
Date: Sat, 21 Mar 2026 17:33:39 -0700
Subject: [PATCH 2/4] Address review comment

---
 clang/lib/Sema/SemaInit.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index a41c1f456efe9..77eb3c0c77bfb 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -4990,6 +4990,9 @@ static void TryReferenceListInitialization(Sema &S,
         // ..., unless T is “reference to array of unknown bound of U”, in which
         // case the type of the prvalue is the type of x in the declaration U
         // x[] H, where H is the initializer list.
+
+        // The call to AddReferenceBindingStep above converts the rvalue to an xvalue.
+        // Convert that xvalue to the incomplete array type.
         Sequence.AddQualificationConversionStep(cv1T1, clang::VK_XValue);
       }
       if (T1Quals.hasAddressSpace())

>From 536d19c4bf10a38d032bcb5585596151b753507e Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at qti.qualcomm.com>
Date: Sat, 21 Mar 2026 23:30:50 -0700
Subject: [PATCH 3/4] Fix formatting

---
 clang/lib/Sema/SemaInit.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 77eb3c0c77bfb..233b5b646d007 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -4991,8 +4991,8 @@ static void TryReferenceListInitialization(Sema &S,
         // case the type of the prvalue is the type of x in the declaration U
         // x[] H, where H is the initializer list.
 
-        // The call to AddReferenceBindingStep above converts the rvalue to an xvalue.
-        // Convert that xvalue to the incomplete array type.
+        // The call to AddReferenceBindingStep above converts the rvalue to an
+        // xvalue. Convert that xvalue to the incomplete array type.
         Sequence.AddQualificationConversionStep(cv1T1, clang::VK_XValue);
       }
       if (T1Quals.hasAddressSpace())

>From 17e9213d9f47d75dcc711a37a95c4f54e5116149 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at qti.qualcomm.com>
Date: Wed, 15 Apr 2026 12:45:24 -0700
Subject: [PATCH 4/4] Add ast-dump test.

---
 clang/test/AST/ast-dump-init.cpp | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 clang/test/AST/ast-dump-init.cpp

diff --git a/clang/test/AST/ast-dump-init.cpp b/clang/test/AST/ast-dump-init.cpp
new file mode 100644
index 0000000000000..dbf95afdccb82
--- /dev/null
+++ b/clang/test/AST/ast-dump-init.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump -std=c++20 %s | FileCheck %s
+
+void foo(int a) {
+  auto f = [](int(&&)[]) {};
+  f({a});
+}
+
+// Make sure the MaterializeTemporaryExpr has a complete type, which is then
+// cast to an incomplete array type.
+
+// CHECK:         `-ExprWithCleanups 0x{{[^ ]*}}{{[^ ]*}} <line:5:3, col:8> 'void'
+// CHECK-NEXT:      `-CXXOperatorCallExpr 0x{{[^ ]*}} <col:3, col:8> 'void' '()'
+// CHECK-NEXT:        |-ImplicitCastExpr 0x{{[^ ]*}} <col:4, col:8> 'void (*)(int (&&)[]) const' <FunctionToPointerDecay>
+// CHECK-NEXT:        | `-DeclRefExpr 0x{{[^ ]*}} <col:4, col:8> 'void (int (&&)[]) const' lvalue CXXMethod 0x{{[^ ]*}} 'operator()' 'void (int (&&)[]) const'
+// CHECK-NEXT:        |-ImplicitCastExpr 0x{{[^ ]*}} <col:3> 'const (lambda at {{.*}})' lvalue <NoOp>
+// CHECK-NEXT:        | `-DeclRefExpr 0x{{[^ ]*}} <col:3> '(lambda at {{.*}})' lvalue Var 0x{{[^ ]*}} 'f' '(lambda at {{.*}})'
+// CHECK-NEXT:        `-ImplicitCastExpr 0x{{[^ ]*}} <col:5, col:7> 'int[]' xvalue <NoOp>
+// CHECK-NEXT:          `-MaterializeTemporaryExpr 0x{{[^ ]*}} <col:5, col:7> 'int[1]' xvalue
+// CHECK-NEXT:            `-InitListExpr 0x{{[^ ]*}} <col:5, col:7> 'int[1]'
+// CHECK-NEXT:              `-ImplicitCastExpr 0x{{[^ ]*}} <col:6> 'int' <LValueToRValue>
+// CHECK-NEXT:                `-DeclRefExpr 0x{{[^ ]*}} <col:6> 'int' lvalue ParmVar 0x{{[^ ]*}} 'a' 'int'



More information about the cfe-commits mailing list