Index: lib/Analysis/ThreadSafetyCommon.cpp =================================================================== --- lib/Analysis/ThreadSafetyCommon.cpp +++ lib/Analysis/ThreadSafetyCommon.cpp @@ -276,18 +276,23 @@ // Function parameters require substitution and/or renaming. if (const auto *PV = dyn_cast_or_null(VD)) { - const auto *FD = - cast(PV->getDeclContext())->getCanonicalDecl(); unsigned I = PV->getFunctionScopeIndex(); - - if (Ctx && Ctx->FunArgs && FD == Ctx->AttrDecl->getCanonicalDecl()) { - // Substitute call arguments for references to function parameters - assert(I < Ctx->NumArgs); - return translate(Ctx->FunArgs[I], Ctx->Prev); + const auto *D = PV->getDeclContext(); + if (Ctx && Ctx->FunArgs) { + const auto *Canonical = Ctx->AttrDecl->getCanonicalDecl(); + if (isa(D) + ? (cast(D)->getCanonicalDecl() == Canonical) + : (cast(D)->getCanonicalDecl() == Canonical)) { + // Substitute call arguments for references to function parameters + assert(I < Ctx->NumArgs); + return translate(Ctx->FunArgs[I], Ctx->Prev); + } } // Map the param back to the param of the original function declaration // for consistent comparisons. - VD = FD->getParamDecl(I); + VD = isa(D) + ? cast(D)->getCanonicalDecl()->getParamDecl(I) + : cast(D)->getCanonicalDecl()->getParamDecl(I); } // For non-local variables, treat it as a reference to a named object. Index: test/SemaObjCXX/no-crash-thread-safety-analysis.mm =================================================================== --- /dev/null +++ test/SemaObjCXX/no-crash-thread-safety-analysis.mm @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -Wno-objc-root-class %s + +// expected-no-diagnostics + +struct __attribute__((capability("mutex"))) MyLock { + void lock() __attribute__((acquire_capability())) {} + void unlock() __attribute__((release_capability())) {} +}; + +template struct __attribute__((scoped_lockable)) Locker { + T &_l; + Locker(T &l) __attribute__((acquire_capability(l))) : _l(l) { _l.lock(); } + ~Locker() __attribute__((release_capability())) { _l.unlock(); } +}; + +struct MyLockable { + MyLock lock; +}; + +@protocol MyProtocolBase; +@protocol MyProtocol +@end + +@interface MyProtocol +@end + +@interface MyProtocol () +- (void)doIt:(struct MyLockable *)myLockable; +@end + +@implementation MyProtocol +- (void)doIt:(struct MyLockable *)myLockable { + Locker lock(myLockable->lock); +} +@end