diff options
author | Erik Pilkington <erik.pilkington@gmail.com> | 2019-01-04 18:33:06 +0000 |
---|---|---|
committer | Erik Pilkington <erik.pilkington@gmail.com> | 2019-01-04 18:33:06 +0000 |
commit | 1e36882b5291d5a7209be4f9c99b9713828afac4 (patch) | |
tree | cd23171fec5d69fd0390b0ad9303f51396072b5c /clang/lib/Sema/SemaDeclAttr.cpp | |
parent | 6153565511338f33506f4615dd5a7d2e4c4ffaa6 (diff) | |
download | bcm5719-llvm-1e36882b5291d5a7209be4f9c99b9713828afac4.tar.gz bcm5719-llvm-1e36882b5291d5a7209be4f9c99b9713828afac4.zip |
[ObjCARC] Add an new attribute, objc_externally_retained
This attribute, called "objc_externally_retained", exposes clang's
notion of pseudo-__strong variables in ARC. Pseudo-strong variables
"borrow" their initializer, meaning that they don't retain/release
it, instead assuming that someone else is keeping their value alive.
If a function is annotated with this attribute, implicitly strong
parameters of that function aren't implicitly retained/released in
the function body, and are implicitly const. This is useful to expose
for performance reasons, most functions don't need the extra safety
of the retain/release, so programmers can opt out as needed.
This attribute can also apply to declarations of local variables,
with similar effect.
Differential revision: https://reviews.llvm.org/D55865
llvm-svn: 350422
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 96 |
1 files changed, 90 insertions, 6 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 63501d92915..d1db71838fe 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -93,6 +93,17 @@ static unsigned getFunctionOrMethodNumParams(const Decl *D) { return cast<ObjCMethodDecl>(D)->param_size(); } +static const ParmVarDecl *getFunctionOrMethodParam(const Decl *D, + unsigned Idx) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + return FD->getParamDecl(Idx); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->getParamDecl(Idx); + if (const auto *BD = dyn_cast<BlockDecl>(D)) + return BD->getParamDecl(Idx); + return nullptr; +} + static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionProtoType>(FnTy)->getParamType(Idx); @@ -103,12 +114,8 @@ static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { } static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { - if (const auto *FD = dyn_cast<FunctionDecl>(D)) - return FD->getParamDecl(Idx)->getSourceRange(); - if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) - return MD->parameters()[Idx]->getSourceRange(); - if (const auto *BD = dyn_cast<BlockDecl>(D)) - return BD->getParamDecl(Idx)->getSourceRange(); + if (auto *PVD = getFunctionOrMethodParam(D, Idx)) + return PVD->getSourceRange(); return SourceRange(); } @@ -6093,6 +6100,79 @@ static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { UninitializedAttr(AL.getLoc(), S.Context, Index)); } +static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD, + bool DiagnoseFailure) { + QualType Ty = VD->getType(); + if (!Ty->isObjCRetainableType()) { + if (DiagnoseFailure) { + S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained) + << 0; + } + return false; + } + + Qualifiers::ObjCLifetime LifetimeQual = Ty.getQualifiers().getObjCLifetime(); + + // Sema::inferObjCARCLifetime must run after processing decl attributes + // (because __block lowers to an attribute), so if the lifetime hasn't been + // explicitly specified, infer it locally now. + if (LifetimeQual == Qualifiers::OCL_None) + LifetimeQual = Ty->getObjCARCImplicitLifetime(); + + // The attributes only really makes sense for __strong variables; ignore any + // attempts to annotate a parameter with any other lifetime qualifier. + if (LifetimeQual != Qualifiers::OCL_Strong) { + if (DiagnoseFailure) { + S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained) + << 1; + } + return false; + } + + // Tampering with the type of a VarDecl here is a bit of a hack, but we need + // to ensure that the variable is 'const' so that we can error on + // modification, which can otherwise over-release. + VD->setType(Ty.withConst()); + VD->setARCPseudoStrong(true); + return true; +} + +static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + if (auto *VD = dyn_cast<VarDecl>(D)) { + assert(!isa<ParmVarDecl>(VD) && "should be diagnosed automatically"); + if (!VD->hasLocalStorage()) { + S.Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained) + << 0; + return; + } + + if (!tryMakeVariablePseudoStrong(S, VD, /*DiagnoseFailure=*/true)) + return; + + handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL); + return; + } + + // If D is a function-like declaration (method, block, or function), then we + // make every parameter psuedo-strong. + for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { + auto *PVD = const_cast<ParmVarDecl *>(getFunctionOrMethodParam(D, I)); + QualType Ty = PVD->getType(); + + // If a user wrote a parameter with __strong explicitly, then assume they + // want "real" strong semantics for that parameter. This works because if + // the parameter was written with __strong, then the strong qualifier will + // be non-local. + if (Ty.getLocalUnqualifiedType().getQualifiers().getObjCLifetime() == + Qualifiers::OCL_Strong) + continue; + + tryMakeVariablePseudoStrong(S, PVD, /*DiagnoseFailure=*/false); + } + handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -6788,6 +6868,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Uninitialized: handleUninitializedAttr(S, D, AL); break; + + case ParsedAttr::AT_ObjCExternallyRetained: + handleObjCExternallyRetainedAttr(S, D, AL); + break; } } |