Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
------------------
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Sema/SemaObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/Sema/SemaCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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))
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/Sema/SemaExprObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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)) {
Expand Down
23 changes: 21 additions & 2 deletions clang/test/SemaObjCXX/arc-type-conversion.mm
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<unsigned long *>(sip);
(void)reinterpret_cast<__strong id *>(ul);
auto *wp = reinterpret_cast<__weak NSString *>(sip);
(void)reinterpret_cast<__strong id *>(wp);
(void)reinterpret_cast<unsigned long *>(csip); // expected-error {{reinterpret_cast from '__strong id const *' to 'unsigned long *' casts away qualifiers}}
(void)reinterpret_cast<const unsigned long *>(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<const __strong id *>(cul);
volatile __strong id *vsip = nullptr;
(void)reinterpret_cast<unsigned long *>(vsip); // expected-error {{reinterpret_cast from '__strong id volatile *' to 'unsigned long *' casts away qualifiers}}
(void)reinterpret_cast<volatile unsigned long *>(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<volatile __strong id *>(vul);
auto uip = reinterpret_cast<uintptr_t>(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,
Expand Down Expand Up @@ -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<NSString **>(static_cast<__strong id *>(vp));
__strong NSString **&si2pref = static_cast<NSString **&>(sip2);
Expand Down