summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
authorErik Pilkington <erik.pilkington@gmail.com>2019-01-04 18:33:06 +0000
committerErik Pilkington <erik.pilkington@gmail.com>2019-01-04 18:33:06 +0000
commit1e36882b5291d5a7209be4f9c99b9713828afac4 (patch)
treecd23171fec5d69fd0390b0ad9303f51396072b5c /clang/lib/Sema/SemaDeclAttr.cpp
parent6153565511338f33506f4615dd5a7d2e4c4ffaa6 (diff)
downloadbcm5719-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.cpp96
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;
}
}
OpenPOWER on IntegriCloud