https://github.com/DataCorrupted updated 
https://github.com/llvm/llvm-project/pull/180817

>From 28cededb56b656d98839ee6449fea4807b2bf26c Mon Sep 17 00:00:00 2001
From: Peter Rong <[email protected]>
Date: Tue, 10 Feb 2026 09:35:41 -0800
Subject: [PATCH 1/6] Reapply "[clang] Fix sema on ObjCLifetime conversion
 (#178524)"

Clang can't handle objc lifetime correctly when casting
We reuse the approach similar to lifetime: First remove it before the
conversion, then add it back.

Add a test

Fixes https://github.com/llvm/llvm-project/issues/177478
---
 clang/docs/ReleaseNotes.rst                   |  4 +-
 clang/lib/Sema/SemaInit.cpp                   | 33 +++++++++---
 .../arc-lifetime-rvalue-ref-binding.mm        | 50 +++++++++++++++++++
 .../arc-lifetime-rvalue-ref-binding.mm        | 39 +++++++++++++++
 4 files changed, 118 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/CodeGenObjCXX/arc-lifetime-rvalue-ref-binding.mm
 create mode 100644 clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a1bb1bd2467b7..d21e236563232 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -278,6 +278,8 @@ Miscellaneous Clang Crashes Fixed
 - Fixed a crash when using loop hint with a value dependent argument inside a
   generic lambda. (#GH172289)
 - Fixed a crash in C++ overload resolution with ``_Atomic``-qualified argument 
types. (#GH170433)
+- Fixed an assertion failure in ObjC++ ARC when binding a ``__strong`` rvalue 
reference to a ``const __autoreleasing`` reference. (#GH178524)
+
 
 OpenACC Specific Changes
 ------------------------
@@ -360,7 +362,7 @@ AST Matchers
 
 clang-format
 ------------
-- Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space 
between the 
+- Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space 
between the
   '-'/'+' and the return type in Objective-C method declarations
 
 libclang
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index ff278bc7471bd..12e9c48ba0c52 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5645,14 +5645,22 @@ static void TryReferenceInitializationCore(Sema &S,
     //   applied.
     // Postpone address space conversions to after the temporary 
materialization
     // conversion to allow creating temporaries in the alloca address space.
-    auto T1QualsIgnoreAS = T1Quals;
-    auto T2QualsIgnoreAS = T2Quals;
+    auto T1QualsIgnoreConversions = T1Quals;
+    auto T2QualsIgnoreConversions = T2Quals;
     if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) {
-      T1QualsIgnoreAS.removeAddressSpace();
-      T2QualsIgnoreAS.removeAddressSpace();
-    }
-    QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1QualsIgnoreAS);
-    if (T1QualsIgnoreAS != T2QualsIgnoreAS)
+      T1QualsIgnoreConversions.removeAddressSpace();
+      T2QualsIgnoreConversions.removeAddressSpace();
+    }
+    // Postpone ObjC lifetime conversions to after the temporary 
materialization
+    // conversion, similar to address space conversions. This handles cases 
like
+    // binding a __strong rvalue to a const __autoreleasing reference.
+    if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime()) {
+      T1QualsIgnoreConversions.removeObjCLifetime();
+      T2QualsIgnoreConversions.removeObjCLifetime();
+    }
+    QualType cv1T4 =
+        S.Context.getQualifiedType(cv2T2, T1QualsIgnoreConversions);
+    if (T1QualsIgnoreConversions != T2QualsIgnoreConversions)
       Sequence.AddQualificationConversionStep(cv1T4, ValueKind);
     Sequence.AddReferenceBindingStep(cv1T4, ValueKind == VK_PRValue);
     ValueKind = isLValueRef ? VK_LValue : VK_XValue;
@@ -5664,6 +5672,17 @@ static void TryReferenceInitializationCore(Sema &S,
       Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind);
       cv1T4 = cv1T4WithAS;
     }
+    // Add ObjC lifetime conversion if required.
+    if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime()) {
+      auto T4Quals = cv1T4.getQualifiers();
+      T4Quals.setObjCLifetime(T1Quals.getObjCLifetime());
+      // Apply T4Quals to the unqualified base type to avoid conflicting
+      // ObjC lifetime qualifiers in getQualifiedType.
+      QualType CV1T4WithLifetime =
+          S.Context.getQualifiedType(cv1T4.getUnqualifiedType(), T4Quals);
+      Sequence.AddQualificationConversionStep(CV1T4WithLifetime, ValueKind);
+      cv1T4 = CV1T4WithLifetime;
+    }
 
     //   In any case, the reference is bound to the resulting glvalue (or to
     //   an appropriate base class subobject).
diff --git a/clang/test/CodeGenObjCXX/arc-lifetime-rvalue-ref-binding.mm 
b/clang/test/CodeGenObjCXX/arc-lifetime-rvalue-ref-binding.mm
new file mode 100644
index 0000000000000..93f87bb8c1d3c
--- /dev/null
+++ b/clang/test/CodeGenObjCXX/arc-lifetime-rvalue-ref-binding.mm
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-apple-darwin10 -emit-llvm 
-fobjc-arc -O0 -disable-llvm-passes -o - %s | FileCheck %s
+
+// Test for correct IR generation when binding ObjC ARC __strong rvalues
+// to const __autoreleasing references. Previously, this caused an assertion
+// failure in Qualifiers::addConsistentQualifiers.
+
+// The const id& parameter has implicit __autoreleasing lifetime.
+void take(const id&);
+
+// CHECK-LABEL: define{{.*}} void @_Z19test_rvalue_bindingv()
+// CHECK: [[OBJ:%.*]] = alloca ptr, align 8
+// CHECK: store ptr null, ptr [[OBJ]], align 8
+// CHECK: call void @_Z4takeRU15__autoreleasingKP11objc_object(ptr noundef 
nonnull align 8 dereferenceable(8) [[OBJ]])
+// CHECK: call void @llvm.objc.storeStrong(ptr [[OBJ]], ptr null)
+// CHECK: ret void
+void test_rvalue_binding() {
+  id obj = nullptr;
+  take(static_cast<id&&>(obj));
+}
+
+// CHECK-LABEL: define{{.*}} void @_Z19test_lvalue_bindingv()
+// CHECK: [[OBJ:%.*]] = alloca ptr, align 8
+// CHECK: store ptr null, ptr [[OBJ]], align 8
+// CHECK: call void @_Z4takeRU15__autoreleasingKP11objc_object(ptr noundef 
nonnull align 8 dereferenceable(8) [[OBJ]])
+// CHECK: call void @llvm.objc.storeStrong(ptr [[OBJ]], ptr null)
+// CHECK: ret void
+void test_lvalue_binding() {
+  id obj = nullptr;
+  take(obj);
+}
+
+// Test with fold expressions and perfect forwarding (original crash case).
+template <typename... Args>
+void call(Args... args) {
+  (take(static_cast<Args&&>(args)), ...);
+}
+
+// CHECK-LABEL: define{{.*}} void @_Z20test_fold_expressionv()
+// CHECK: call void @_Z4callIJU8__strongP11objc_objectEEvDpT_(ptr noundef null)
+void test_fold_expression() {
+  call<id>(nullptr);
+}
+
+// CHECK-LABEL: define{{.*}} void 
@_Z4callIJU8__strongP11objc_objectEEvDpT_(ptr noundef %args)
+// CHECK: [[ARGS_ADDR:%.*]] = alloca ptr, align 8
+// CHECK: store ptr null, ptr [[ARGS_ADDR]], align 8
+// CHECK: call void @llvm.objc.storeStrong(ptr [[ARGS_ADDR]], ptr %args)
+// CHECK: call void @_Z4takeRU15__autoreleasingKP11objc_object(ptr noundef 
nonnull align 8 dereferenceable(8) [[ARGS_ADDR]])
+// CHECK: call void @llvm.objc.storeStrong(ptr [[ARGS_ADDR]], ptr null)
+// CHECK: ret void
diff --git a/clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm 
b/clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm
new file mode 100644
index 0000000000000..5db3f59f8fa08
--- /dev/null
+++ b/clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -std=c++17 -fobjc-arc -ast-dump %s 2>&1 | FileCheck %s
+// expected-no-diagnostics
+
+// Test for binding ObjC ARC __strong rvalues to const __autoreleasing 
references.
+// This previously caused an assertion failure in 
Qualifiers::addConsistentQualifiers
+// when the compiler attempted to add conflicting ObjC lifetime qualifiers.
+
+// The const id& parameter has implicit __autoreleasing lifetime.
+void take(const id&);
+
+// CHECK-LABEL: FunctionDecl {{.*}} test_rvalue_binding
+// CHECK: CallExpr
+// CHECK: ImplicitCastExpr {{.*}} 'const __autoreleasing id' lvalue <NoOp>
+// CHECK-NEXT: CXXStaticCastExpr {{.*}} '__strong id' xvalue 
static_cast<__strong id &&> <NoOp>
+void test_rvalue_binding() {
+  id obj = nullptr;
+  take(static_cast<id&&>(obj));
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} test_lvalue_binding
+// CHECK: CallExpr
+// CHECK: ImplicitCastExpr {{.*}} 'const __autoreleasing id' lvalue <NoOp>
+// CHECK-NEXT: DeclRefExpr {{.*}} '__strong id' lvalue
+void test_lvalue_binding() {
+  id obj = nullptr;
+  take(obj);
+}
+
+// Test with fold expressions and perfect forwarding (original crash case).
+template <typename... Args>
+void call(Args... args) {
+  (take(static_cast<Args&&>(args)), ...);
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} test_fold_expression
+void test_fold_expression() {
+  call<id>(nullptr);
+}

>From 82375996fb8ec124e0e13b4e64c8bdacda90de23 Mon Sep 17 00:00:00 2001
From: Peter Rong <[email protected]>
Date: Tue, 10 Feb 2026 11:47:08 -0800
Subject: [PATCH 2/6] format

---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d21e236563232..458f32c9cf974 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -362,7 +362,7 @@ AST Matchers
 
 clang-format
 ------------
-- Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space 
between the
+- Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space 
between the 
   '-'/'+' and the return type in Objective-C method declarations
 
 libclang

>From da5b72d0437519f01878bfd9008d25951664db31 Mon Sep 17 00:00:00 2001
From: Peter Rong <[email protected]>
Date: Wed, 11 Feb 2026 13:43:01 -0800
Subject: [PATCH 3/6] new fix, address reviewer's concern, and add more test

---
 clang/lib/Sema/SemaInit.cpp                   | 44 +++++++++----------
 .../arc-lifetime-rvalue-ref-binding.mm        | 19 ++++++++
 .../arc-lifetime-rvalue-ref-binding.mm        |  2 +-
 3 files changed, 40 insertions(+), 25 deletions(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 12e9c48ba0c52..89e769f8ef21c 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5645,22 +5645,29 @@ static void TryReferenceInitializationCore(Sema &S,
     //   applied.
     // Postpone address space conversions to after the temporary 
materialization
     // conversion to allow creating temporaries in the alloca address space.
-    auto T1QualsIgnoreConversions = T1Quals;
-    auto T2QualsIgnoreConversions = T2Quals;
+    auto T1QualsIgnoreAS = T1Quals;
+    auto T2QualsIgnoreAS = T2Quals;
     if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) {
-      T1QualsIgnoreConversions.removeAddressSpace();
-      T2QualsIgnoreConversions.removeAddressSpace();
-    }
-    // Postpone ObjC lifetime conversions to after the temporary 
materialization
-    // conversion, similar to address space conversions. This handles cases 
like
-    // binding a __strong rvalue to a const __autoreleasing reference.
+      T1QualsIgnoreAS.removeAddressSpace();
+      T2QualsIgnoreAS.removeAddressSpace();
+    }
+    // Strip the existing ObjC lifetime qualifier from cv2T2 before combining
+    // with T1's qualifiers. getQualifiedType adds qualifiers on top of
+    // existing ones, so if cv2T2 already carries e.g. __strong and T1Quals
+    // has __autoreleasing, we'd hit an assertion in addConsistentQualifiers.
+    // Stripping first and then applying T1's qualifiers ensures the correct
+    // lifetime is set *before* reference binding, which is critical for
+    // CodeGen to emit the right ARC semantics (e.g. retain+autorelease for
+    // __autoreleasing, not retain+release as for __strong).
+    QualType T2ForQualConv = cv2T2;
     if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime()) {
-      T1QualsIgnoreConversions.removeObjCLifetime();
-      T2QualsIgnoreConversions.removeObjCLifetime();
+      Qualifiers T2BaseQuals = T2ForQualConv.getQualifiers();
+      T2BaseQuals.removeObjCLifetime();
+      T2ForQualConv = S.Context.getQualifiedType(
+          T2ForQualConv.getUnqualifiedType(), T2BaseQuals);
     }
-    QualType cv1T4 =
-        S.Context.getQualifiedType(cv2T2, T1QualsIgnoreConversions);
-    if (T1QualsIgnoreConversions != T2QualsIgnoreConversions)
+    QualType cv1T4 = S.Context.getQualifiedType(T2ForQualConv, 
T1QualsIgnoreAS);
+    if (T1QualsIgnoreAS != T2QualsIgnoreAS)
       Sequence.AddQualificationConversionStep(cv1T4, ValueKind);
     Sequence.AddReferenceBindingStep(cv1T4, ValueKind == VK_PRValue);
     ValueKind = isLValueRef ? VK_LValue : VK_XValue;
@@ -5672,17 +5679,6 @@ static void TryReferenceInitializationCore(Sema &S,
       Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind);
       cv1T4 = cv1T4WithAS;
     }
-    // Add ObjC lifetime conversion if required.
-    if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime()) {
-      auto T4Quals = cv1T4.getQualifiers();
-      T4Quals.setObjCLifetime(T1Quals.getObjCLifetime());
-      // Apply T4Quals to the unqualified base type to avoid conflicting
-      // ObjC lifetime qualifiers in getQualifiedType.
-      QualType CV1T4WithLifetime =
-          S.Context.getQualifiedType(cv1T4.getUnqualifiedType(), T4Quals);
-      Sequence.AddQualificationConversionStep(CV1T4WithLifetime, ValueKind);
-      cv1T4 = CV1T4WithLifetime;
-    }
 
     //   In any case, the reference is bound to the resulting glvalue (or to
     //   an appropriate base class subobject).
diff --git a/clang/test/CodeGenObjCXX/arc-lifetime-rvalue-ref-binding.mm 
b/clang/test/CodeGenObjCXX/arc-lifetime-rvalue-ref-binding.mm
index 93f87bb8c1d3c..71412a115b8ae 100644
--- a/clang/test/CodeGenObjCXX/arc-lifetime-rvalue-ref-binding.mm
+++ b/clang/test/CodeGenObjCXX/arc-lifetime-rvalue-ref-binding.mm
@@ -48,3 +48,22 @@ void test_fold_expression() {
 // CHECK: call void @_Z4takeRU15__autoreleasingKP11objc_object(ptr noundef 
nonnull align 8 dereferenceable(8) [[ARGS_ADDR]])
 // CHECK: call void @llvm.objc.storeStrong(ptr [[ARGS_ADDR]], ptr null)
 // CHECK: ret void
+
+// Test that binding a prvalue to an __autoreleasing rvalue reference emits
+// retain+autorelease (not retain+release), per ARC semantics for 
__autoreleasing.
+// CHECK-LABEL: define{{.*}} void 
@_Z32test_autoreleasing_rvalue_ref_prP11objc_object(ptr noundef %a)
+// CHECK: [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK: [[R:%.*]] = alloca ptr, align 8
+// CHECK: [[REF_TMP:%.*]] = alloca ptr, align 8
+// CHECK: store ptr null, ptr [[A_ADDR]], align 8
+// CHECK: call void @llvm.objc.storeStrong(ptr [[A_ADDR]], ptr %a)
+// CHECK: [[LOAD:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// CHECK: [[RETAINED:%.*]] = call ptr @llvm.objc.retain(ptr [[LOAD]])
+// CHECK: [[AUTORELEASED:%.*]] = call ptr @llvm.objc.autorelease(ptr 
[[RETAINED]])
+// CHECK: store ptr [[AUTORELEASED]], ptr [[REF_TMP]], align 8
+// CHECK: store ptr [[REF_TMP]], ptr [[R]], align 8
+// CHECK: call void @llvm.objc.storeStrong(ptr [[A_ADDR]], ptr null)
+// CHECK: ret void
+void test_autoreleasing_rvalue_ref_pr(id a) {
+  id __autoreleasing && r = id{a};
+}
diff --git a/clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm 
b/clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm
index 5db3f59f8fa08..d6d9c4a6289ee 100644
--- a/clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm
+++ b/clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm
@@ -11,7 +11,7 @@
 
 // CHECK-LABEL: FunctionDecl {{.*}} test_rvalue_binding
 // CHECK: CallExpr
-// CHECK: ImplicitCastExpr {{.*}} 'const __autoreleasing id' lvalue <NoOp>
+// CHECK: ImplicitCastExpr {{.*}} 'const __autoreleasing id' xvalue <NoOp>
 // CHECK-NEXT: CXXStaticCastExpr {{.*}} '__strong id' xvalue 
static_cast<__strong id &&> <NoOp>
 void test_rvalue_binding() {
   id obj = nullptr;

>From e7d792781e1735a13bb7f842fe3295ac657e0bd7 Mon Sep 17 00:00:00 2001
From: Peter Rong <[email protected]>
Date: Wed, 11 Feb 2026 13:50:14 -0800
Subject: [PATCH 4/6] comment

---
 clang/lib/Sema/SemaInit.cpp | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 89e769f8ef21c..fa234fb498e59 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5652,13 +5652,7 @@ static void TryReferenceInitializationCore(Sema &S,
       T2QualsIgnoreAS.removeAddressSpace();
     }
     // Strip the existing ObjC lifetime qualifier from cv2T2 before combining
-    // with T1's qualifiers. getQualifiedType adds qualifiers on top of
-    // existing ones, so if cv2T2 already carries e.g. __strong and T1Quals
-    // has __autoreleasing, we'd hit an assertion in addConsistentQualifiers.
-    // Stripping first and then applying T1's qualifiers ensures the correct
-    // lifetime is set *before* reference binding, which is critical for
-    // CodeGen to emit the right ARC semantics (e.g. retain+autorelease for
-    // __autoreleasing, not retain+release as for __strong).
+    // with T1's qualifiers.
     QualType T2ForQualConv = cv2T2;
     if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime()) {
       Qualifiers T2BaseQuals = T2ForQualConv.getQualifiers();

>From 550ffc24ae15b5dde7e56cc78667b10a2b4997fd Mon Sep 17 00:00:00 2001
From: Peter Rong <[email protected]>
Date: Thu, 12 Feb 2026 11:04:59 -0800
Subject: [PATCH 5/6] update docs

---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 458f32c9cf974..8234ea83e1f0d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -278,7 +278,7 @@ Miscellaneous Clang Crashes Fixed
 - Fixed a crash when using loop hint with a value dependent argument inside a
   generic lambda. (#GH172289)
 - Fixed a crash in C++ overload resolution with ``_Atomic``-qualified argument 
types. (#GH170433)
-- Fixed an assertion failure in ObjC++ ARC when binding a ``__strong`` rvalue 
reference to a ``const __autoreleasing`` reference. (#GH178524)
+- Fixed an assertion failure in ObjC++ ARC when binding a rvalue reference to 
reference with different lifetimes (#GH178524)
 
 
 OpenACC Specific Changes

>From 7d5b1d3745c5651a54832e4f016f50770892f2fb Mon Sep 17 00:00:00 2001
From: Peter Rong <[email protected]>
Date: Thu, 12 Feb 2026 11:34:44 -0800
Subject: [PATCH 6/6] simplify

---
 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 fa234fb498e59..989f7cd80cbef 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5655,8 +5655,8 @@ static void TryReferenceInitializationCore(Sema &S,
     // with T1's qualifiers.
     QualType T2ForQualConv = cv2T2;
     if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime()) {
-      Qualifiers T2BaseQuals = T2ForQualConv.getQualifiers();
-      T2BaseQuals.removeObjCLifetime();
+      Qualifiers T2BaseQuals =
+          T2ForQualConv.getQualifiers().withoutObjCLifetime();
       T2ForQualConv = S.Context.getQualifiedType(
           T2ForQualConv.getUnqualifiedType(), T2BaseQuals);
     }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to