diff options
| author | Akira Hatanaka <ahatanaka@apple.com> | 2017-01-26 18:13:06 +0000 |
|---|---|---|
| committer | Akira Hatanaka <ahatanaka@apple.com> | 2017-01-26 18:13:06 +0000 |
| commit | 5d55a6c69d083146112a2ed0152a427346083ffd (patch) | |
| tree | 4867799045180b6b0c2568aaa35c29bef4c1d51e | |
| parent | 61da067393b1c7151d30c382a6e5b1b5befe4975 (diff) | |
| download | bcm5719-llvm-5d55a6c69d083146112a2ed0152a427346083ffd.tar.gz bcm5719-llvm-5d55a6c69d083146112a2ed0152a427346083ffd.zip | |
[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
llvm-svn: 293194
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 23 | ||||
| -rw-r--r-- | clang/test/SemaObjC/arc.m | 23 |
2 files changed, 42 insertions, 4 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 388420cc1ba..be97e27ae6d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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<PointerType>(CaptureType)) { + if (const auto *PT = CaptureType->getAs<PointerType>()) { + // 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<AttributedType>()) { + 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<ObjCObjectPointerType>(PointeeTy.getCanonicalType()) && + + if (PointeeTy->getAs<ObjCObjectPointerType>() && PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing && - !isa<AttributedType>(PointeeTy)) { + !IsObjCOwnershipAttributedType(PointeeTy)) { if (BuildAndDiagnose) { SourceLocation VarLoc = Var->getLocation(); S.Diag(Loc, diag::warn_block_capture_autoreleasing); diff --git a/clang/test/SemaObjC/arc.m b/clang/test/SemaObjC/arc.m index f463bb03b07..2aeecdb4440 100644 --- a/clang/test/SemaObjC/arc.m +++ b/clang/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; }(); } |

