https://github.com/DataCorrupted updated https://github.com/llvm/llvm-project/pull/178524
>From f57c297bc41117d67a5d89d06f78ac2b030b4de3 Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Thu, 22 Jan 2026 14:48:30 -0800 Subject: [PATCH 1/2] [clang] Fix sema clang can't handle objc lifetime correctly when casting add a test --- clang/lib/Sema/SemaInit.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index ff278bc7471bd..117c2e4e6674d 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5651,6 +5651,13 @@ static void TryReferenceInitializationCore(Sema &S, T1QualsIgnoreAS.removeAddressSpace(); T2QualsIgnoreAS.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()) { + T1QualsIgnoreAS.removeObjCLifetime(); + T2QualsIgnoreAS.removeObjCLifetime(); + } QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1QualsIgnoreAS); if (T1QualsIgnoreAS != T2QualsIgnoreAS) Sequence.AddQualificationConversionStep(cv1T4, ValueKind); @@ -5664,6 +5671,14 @@ 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()); + QualType cv1T4WithLifetime = S.Context.getQualifiedType(T2, 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). >From bea74c7aabe1bd5f2eba2567c374c6be3047bbcc Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Thu, 22 Jan 2026 14:48:30 -0800 Subject: [PATCH 2/2] Address reviewers --- clang/lib/Sema/SemaInit.cpp | 22 ++++++----- .../arc-lifetime-rvalue-ref-binding.mm | 39 +++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 clang/test/SemaObjCXX/arc-lifetime-rvalue-ref-binding.mm diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 117c2e4e6674d..fad1a7775dc5c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5645,21 +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 T1QualsIgnoreConvertions = T1Quals; + auto T2QualsIgnoreConvertions = T2Quals; if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) { - T1QualsIgnoreAS.removeAddressSpace(); - T2QualsIgnoreAS.removeAddressSpace(); + T1QualsIgnoreConvertions.removeAddressSpace(); + T2QualsIgnoreConvertions.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()) { - T1QualsIgnoreAS.removeObjCLifetime(); - T2QualsIgnoreAS.removeObjCLifetime(); + T1QualsIgnoreConvertions.removeObjCLifetime(); + T2QualsIgnoreConvertions.removeObjCLifetime(); } - QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1QualsIgnoreAS); - if (T1QualsIgnoreAS != T2QualsIgnoreAS) + QualType cv1T4 = + S.Context.getQualifiedType(cv2T2, T1QualsIgnoreConvertions); + if (T1QualsIgnoreConvertions != T2QualsIgnoreConvertions) Sequence.AddQualificationConversionStep(cv1T4, ValueKind); Sequence.AddReferenceBindingStep(cv1T4, ValueKind == VK_PRValue); ValueKind = isLValueRef ? VK_LValue : VK_XValue; @@ -5675,7 +5676,10 @@ static void TryReferenceInitializationCore(Sema &S, if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime()) { auto T4Quals = cv1T4.getQualifiers(); T4Quals.setObjCLifetime(T1Quals.getObjCLifetime()); - QualType cv1T4WithLifetime = S.Context.getQualifiedType(T2, T4Quals); + // 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; } 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); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
