Skip to content

Commit 40d2f39

Browse files
authored
[Sema][ObjC] Loosen restrictions on reinterpret_cast involving indirect ARC-managed pointers (#144458)
Allow using reinterpret_cast for conversions between indirect ARC pointers and other pointer types. rdar://152905399
1 parent 9db7502 commit 40d2f39

File tree

5 files changed

+41
-11
lines changed

5 files changed

+41
-11
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ Non-comprehensive list of changes in this release
327327
``__reference_constructs_from_temporary`` should be used instead. (#GH44056)
328328
- Added `__builtin_get_vtable_pointer` to directly load the primary vtable pointer from a
329329
polymorphic object.
330+
- Clang no longer rejects reinterpret_cast conversions between indirect
331+
ARC-managed pointers and other pointer types. The prior behavior was overly
332+
strict and inconsistent with the ARC specification.
330333

331334
New Compiler Flags
332335
------------------

clang/include/clang/Sema/SemaObjC.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,8 @@ class SemaObjC : public SemaBase {
812812
CheckedConversionKind CCK,
813813
bool Diagnose = true,
814814
bool DiagnoseCFAudited = false,
815-
BinaryOperatorKind Opc = BO_PtrMemD);
815+
BinaryOperatorKind Opc = BO_PtrMemD,
816+
bool IsReinterpretCast = false);
816817

817818
Expr *stripARCUnbridgedCast(Expr *e);
818819
void diagnoseARCUnbridgedCast(Expr *e);

clang/lib/Sema/SemaCast.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,14 @@ namespace {
161161
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
162162
}
163163

164-
void checkObjCConversion(CheckedConversionKind CCK) {
164+
void checkObjCConversion(CheckedConversionKind CCK,
165+
bool IsReinterpretCast = false) {
165166
assert(Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers());
166167

167168
Expr *src = SrcExpr.get();
168-
if (Self.ObjC().CheckObjCConversion(OpRange, DestType, src, CCK) ==
169-
SemaObjC::ACR_unbridged)
169+
if (Self.ObjC().CheckObjCConversion(
170+
OpRange, DestType, src, CCK, true, false, BO_PtrMemD,
171+
IsReinterpretCast) == SemaObjC::ACR_unbridged)
170172
IsARCUnbridgedCast = true;
171173
SrcExpr = src;
172174
}
@@ -1263,7 +1265,8 @@ void CastOperation::CheckReinterpretCast() {
12631265

12641266
if (isValidCast(tcr)) {
12651267
if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
1266-
checkObjCConversion(CheckedConversionKind::OtherCast);
1268+
checkObjCConversion(CheckedConversionKind::OtherCast,
1269+
/*IsReinterpretCast=*/true);
12671270
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
12681271

12691272
if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType))

clang/lib/Sema/SemaExprObjC.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4390,7 +4390,7 @@ SemaObjC::ARCConversionResult
43904390
SemaObjC::CheckObjCConversion(SourceRange castRange, QualType castType,
43914391
Expr *&castExpr, CheckedConversionKind CCK,
43924392
bool Diagnose, bool DiagnoseCFAudited,
4393-
BinaryOperatorKind Opc) {
4393+
BinaryOperatorKind Opc, bool IsReinterpretCast) {
43944394
ASTContext &Context = getASTContext();
43954395
QualType castExprType = castExpr->getType();
43964396

@@ -4450,13 +4450,17 @@ SemaObjC::CheckObjCConversion(SourceRange castRange, QualType castType,
44504450
// must be explicit.
44514451
// Allow conversions between pointers to lifetime types and coreFoundation
44524452
// pointers too, but only when the conversions are explicit.
4453+
// Allow conversions requested with a reinterpret_cast that converts an
4454+
// expression of type T* to type U*.
44534455
if (exprACTC == ACTC_indirectRetainable &&
44544456
(castACTC == ACTC_voidPtr ||
4455-
(castACTC == ACTC_coreFoundation && SemaRef.isCast(CCK))))
4457+
(castACTC == ACTC_coreFoundation && SemaRef.isCast(CCK)) ||
4458+
(IsReinterpretCast && effCastType->isAnyPointerType())))
44564459
return ACR_okay;
44574460
if (castACTC == ACTC_indirectRetainable &&
4458-
(exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) &&
4459-
SemaRef.isCast(CCK))
4461+
(((exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) &&
4462+
SemaRef.isCast(CCK)) ||
4463+
(IsReinterpretCast && castExprType->isAnyPointerType())))
44604464
return ACR_okay;
44614465

44624466
switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) {

clang/test/SemaObjCXX/arc-type-conversion.mm

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
22

3+
@class NSString;
4+
typedef unsigned __INTPTR_TYPE__ uintptr_t;
5+
36
void * cvt(id arg) // expected-note{{candidate function not viable: cannot convert argument of incomplete type 'void *' to '__strong id'}}
47
{
58
void* voidp_val;
@@ -72,6 +75,24 @@ void test_reinterpret_cast(__strong id *sip, __weak id *wip,
7275
(void)reinterpret_cast<__weak id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__weak id *' casts away qualifiers}}
7376
(void)reinterpret_cast<__weak id *>(csip); // expected-error{{reinterpret_cast from '__strong id const *' to '__weak id *' casts away qualifiers}}
7477
(void)reinterpret_cast<__strong id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__strong id *' casts away qualifiers}}
78+
79+
auto *ul = reinterpret_cast<unsigned long *>(sip);
80+
(void)reinterpret_cast<__strong id *>(ul);
81+
auto *wp = reinterpret_cast<__weak NSString *>(sip);
82+
(void)reinterpret_cast<__strong id *>(wp);
83+
(void)reinterpret_cast<unsigned long *>(csip); // expected-error {{reinterpret_cast from '__strong id const *' to 'unsigned long *' casts away qualifiers}}
84+
(void)reinterpret_cast<const unsigned long *>(csip);
85+
const unsigned long *cul = nullptr;
86+
(void)reinterpret_cast<__strong id *>(cul); // expected-error {{reinterpret_cast from 'const unsigned long *' to '__strong id *' casts away qualifiers}}
87+
(void)reinterpret_cast<const __strong id *>(cul);
88+
volatile __strong id *vsip = nullptr;
89+
(void)reinterpret_cast<unsigned long *>(vsip); // expected-error {{reinterpret_cast from '__strong id volatile *' to 'unsigned long *' casts away qualifiers}}
90+
(void)reinterpret_cast<volatile unsigned long *>(vsip);
91+
volatile unsigned long *vul = nullptr;
92+
(void)reinterpret_cast<__strong id *>(vul); // expected-error {{reinterpret_cast from 'volatile unsigned long *' to '__strong id *' casts away qualifiers}}
93+
(void)reinterpret_cast<volatile __strong id *>(vul);
94+
auto uip = reinterpret_cast<uintptr_t>(sip);
95+
(void)reinterpret_cast<__strong id *>(uip); // expected-error {{to '__strong id *' is disallowed with ARC}}
7596
}
7697

7798
void test_cstyle_cast(__strong id *sip, __weak id *wip,
@@ -194,8 +215,6 @@ void from_void(void *vp) {
194215
typedef void (^Block_strong)() __strong;
195216
typedef void (^Block_autoreleasing)() __autoreleasing;
196217

197-
@class NSString;
198-
199218
void ownership_transfer_in_cast(void *vp, Block *pblk) {
200219
__strong NSString **sip2 = static_cast<NSString **>(static_cast<__strong id *>(vp));
201220
__strong NSString **&si2pref = static_cast<NSString **&>(sip2);

0 commit comments

Comments
 (0)