diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 59d9612268d30..bea39088c6380 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -325,6 +325,9 @@ Non-comprehensive list of changes in this release ``__reference_constructs_from_temporary`` should be used instead. (#GH44056) - Added `__builtin_get_vtable_pointer` to directly load the primary vtable pointer from a polymorphic object. +- Clang no longer rejects reinterpret_cast conversions between indirect + ARC-managed pointers and other pointer types. The prior behavior was overly + strict and inconsistent with the ARC specification. New Compiler Flags ------------------ diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index b629c6d291402..ed08ff0acf89d 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -812,7 +812,8 @@ class SemaObjC : public SemaBase { CheckedConversionKind CCK, bool Diagnose = true, bool DiagnoseCFAudited = false, - BinaryOperatorKind Opc = BO_PtrMemD); + BinaryOperatorKind Opc = BO_PtrMemD, + bool IsReinterpretCast = false); Expr *stripARCUnbridgedCast(Expr *e); void diagnoseARCUnbridgedCast(Expr *e); diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 14e16bc39eb3a..e15a43c116516 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -161,12 +161,14 @@ namespace { Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); } - void checkObjCConversion(CheckedConversionKind CCK) { + void checkObjCConversion(CheckedConversionKind CCK, + bool IsReinterpretCast = false) { assert(Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()); Expr *src = SrcExpr.get(); - if (Self.ObjC().CheckObjCConversion(OpRange, DestType, src, CCK) == - SemaObjC::ACR_unbridged) + if (Self.ObjC().CheckObjCConversion( + OpRange, DestType, src, CCK, true, false, BO_PtrMemD, + IsReinterpretCast) == SemaObjC::ACR_unbridged) IsARCUnbridgedCast = true; SrcExpr = src; } @@ -1263,7 +1265,8 @@ void CastOperation::CheckReinterpretCast() { if (isValidCast(tcr)) { if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) - checkObjCConversion(CheckedConversionKind::OtherCast); + checkObjCConversion(CheckedConversionKind::OtherCast, + /*IsReinterpretCast=*/true); DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange); if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType)) diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 3505d9f38d23c..395f2f340dbd6 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -4390,7 +4390,7 @@ SemaObjC::ARCConversionResult SemaObjC::CheckObjCConversion(SourceRange castRange, QualType castType, Expr *&castExpr, CheckedConversionKind CCK, bool Diagnose, bool DiagnoseCFAudited, - BinaryOperatorKind Opc) { + BinaryOperatorKind Opc, bool IsReinterpretCast) { ASTContext &Context = getASTContext(); QualType castExprType = castExpr->getType(); @@ -4450,13 +4450,17 @@ SemaObjC::CheckObjCConversion(SourceRange castRange, QualType castType, // must be explicit. // Allow conversions between pointers to lifetime types and coreFoundation // pointers too, but only when the conversions are explicit. + // Allow conversions requested with a reinterpret_cast that converts an + // expression of type T* to type U*. if (exprACTC == ACTC_indirectRetainable && (castACTC == ACTC_voidPtr || - (castACTC == ACTC_coreFoundation && SemaRef.isCast(CCK)))) + (castACTC == ACTC_coreFoundation && SemaRef.isCast(CCK)) || + (IsReinterpretCast && effCastType->isAnyPointerType()))) return ACR_okay; if (castACTC == ACTC_indirectRetainable && - (exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) && - SemaRef.isCast(CCK)) + (((exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) && + SemaRef.isCast(CCK)) || + (IsReinterpretCast && castExprType->isAnyPointerType()))) return ACR_okay; switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) { diff --git a/clang/test/SemaObjCXX/arc-type-conversion.mm b/clang/test/SemaObjCXX/arc-type-conversion.mm index 64cfd02ec18c0..0d281bf3e5c45 100644 --- a/clang/test/SemaObjCXX/arc-type-conversion.mm +++ b/clang/test/SemaObjCXX/arc-type-conversion.mm @@ -1,5 +1,8 @@ // RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s +@class NSString; +typedef unsigned __INTPTR_TYPE__ uintptr_t; + void * cvt(id arg) // expected-note{{candidate function not viable: cannot convert argument of incomplete type 'void *' to '__strong id'}} { void* voidp_val; @@ -72,6 +75,24 @@ void test_reinterpret_cast(__strong id *sip, __weak id *wip, (void)reinterpret_cast<__weak id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__weak id *' casts away qualifiers}} (void)reinterpret_cast<__weak id *>(csip); // expected-error{{reinterpret_cast from '__strong id const *' to '__weak id *' casts away qualifiers}} (void)reinterpret_cast<__strong id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__strong id *' casts away qualifiers}} + + auto *ul = reinterpret_cast(sip); + (void)reinterpret_cast<__strong id *>(ul); + auto *wp = reinterpret_cast<__weak NSString *>(sip); + (void)reinterpret_cast<__strong id *>(wp); + (void)reinterpret_cast(csip); // expected-error {{reinterpret_cast from '__strong id const *' to 'unsigned long *' casts away qualifiers}} + (void)reinterpret_cast(csip); + const unsigned long *cul = nullptr; + (void)reinterpret_cast<__strong id *>(cul); // expected-error {{reinterpret_cast from 'const unsigned long *' to '__strong id *' casts away qualifiers}} + (void)reinterpret_cast(cul); + volatile __strong id *vsip = nullptr; + (void)reinterpret_cast(vsip); // expected-error {{reinterpret_cast from '__strong id volatile *' to 'unsigned long *' casts away qualifiers}} + (void)reinterpret_cast(vsip); + volatile unsigned long *vul = nullptr; + (void)reinterpret_cast<__strong id *>(vul); // expected-error {{reinterpret_cast from 'volatile unsigned long *' to '__strong id *' casts away qualifiers}} + (void)reinterpret_cast(vul); + auto uip = reinterpret_cast(sip); + (void)reinterpret_cast<__strong id *>(uip); // expected-error {{to '__strong id *' is disallowed with ARC}} } void test_cstyle_cast(__strong id *sip, __weak id *wip, @@ -194,8 +215,6 @@ void from_void(void *vp) { typedef void (^Block_strong)() __strong; typedef void (^Block_autoreleasing)() __autoreleasing; -@class NSString; - void ownership_transfer_in_cast(void *vp, Block *pblk) { __strong NSString **sip2 = static_cast(static_cast<__strong id *>(vp)); __strong NSString **&si2pref = static_cast(sip2);