From 3322605b76b54d4bdcd1e5074c007c777414e300 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Thu, 26 Jan 2017 18:13:06 +0000 Subject: [PATCH] [Sema][ObjC] Make sure -Wblock-capture-autoreleasing issues a warning even in the presence of nullability qualifiers. This commit fixes bugs in r285031 where -Wblock-capture-autoreleasing wouldn't issue warnings when the function parameters were annotated with nullability qualifiers. Specifically, look through the sugar and see if there is an AttributedType of kind attr_objc_ownership to determine whether __autoreleasing was explicitly specified or implicitly added by the compiler. rdar://problem/30193488 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@293194 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExpr.cpp | 23 ++++++++++++++++++++--- test/SemaObjC/arc.m | 23 ++++++++++++++++++++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 388420cc1b..be97e27ae6 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -13603,11 +13603,28 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, } // Warn about implicitly autoreleasing indirect parameters captured by blocks. - if (auto *PT = dyn_cast(CaptureType)) { + if (const auto *PT = CaptureType->getAs()) { + // This function finds out whether there is an AttributedType of kind + // attr_objc_ownership in Ty. The existence of AttributedType of kind + // attr_objc_ownership implies __autoreleasing was explicitly specified + // rather than being added implicitly by the compiler. + auto IsObjCOwnershipAttributedType = [](QualType Ty) { + while (const auto *AttrTy = Ty->getAs()) { + if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership) + return true; + + // Peel off AttributedTypes that are not of kind objc_ownership. + Ty = AttrTy->getModifiedType(); + } + + return false; + }; + QualType PointeeTy = PT->getPointeeType(); - if (isa(PointeeTy.getCanonicalType()) && + + if (PointeeTy->getAs() && PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing && - !isa(PointeeTy)) { + !IsObjCOwnershipAttributedType(PointeeTy)) { if (BuildAndDiagnose) { SourceLocation VarLoc = Var->getLocation(); S.Diag(Loc, diag::warn_block_capture_autoreleasing); diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m index f463bb03b0..2aeecdb444 100644 --- a/test/SemaObjC/arc.m +++ b/test/SemaObjC/arc.m @@ -809,9 +809,30 @@ int garf() { TKAssertEqual(object, (id)nil); } -void block_capture_autoreleasing(A * __autoreleasing *a, A **b) { // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}} +void block_capture_autoreleasing(A * __autoreleasing *a, + A **b, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}} + A * _Nullable *c, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}} + A * _Nullable __autoreleasing *d, + A ** _Nullable e, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}} + A * __autoreleasing * _Nullable f, + id __autoreleasing *g, + id *h, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}} + id _Nullable *i, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}} + id _Nullable __autoreleasing *j, + id * _Nullable k, // expected-note {{declare the parameter __autoreleasing explicitly to suppress this warning}} expected-note {{declare the parameter __strong or capture a __block __strong variable to keep values alive across autorelease pools}} + id __autoreleasing * _Nullable l) { ^{ (void)*a; (void)*b; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}} + (void)*c; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}} + (void)*d; + (void)*e; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}} + (void)*f; + (void)*g; + (void)*h; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}} + (void)*i; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}} + (void)*j; + (void)*k; // expected-warning {{block captures an autoreleasing out-parameter, which may result in use-after-free bugs}} + (void)*l; }(); } -- 2.40.0