erik.pilkington updated this revision to Diff 178928.
erik.pilkington marked 10 inline comments as done.
erik.pilkington added a comment.
Address @aaron.ballman comments, rebase onto r349535. Thanks!
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D55865/new/
https://reviews.llvm.org/D55865
Files:
clang/include/clang/AST/Decl.h
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/CodeGen/CGDecl.cpp
clang/lib/CodeGen/CGExpr.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/CodeGenObjC/externally-retained.m
clang/test/Misc/pragma-attribute-supported-attributes-list.test
clang/test/SemaObjC/externally-retained.m
Index: clang/test/SemaObjC/externally-retained.m
===================================================================
--- /dev/null
+++ clang/test/SemaObjC/externally-retained.m
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -fobjc-runtime=macosx-10.13.0 -fblocks -fobjc-arc %s -verify
+
+#define EXT_RET __attribute__((objc_externally_retained))
+
+@interface ObjCTy
+@end
+
+void test1() {
+ EXT_RET int a; // expected-warning{{'objc_externally_retained' can only be applied to}}
+ EXT_RET __weak ObjCTy *b; // expected-warning{{'objc_externally_retained' can only be applied to}}
+ EXT_RET __weak int (^c)(); // expected-warning{{'objc_externally_retained' can only be applied to}}
+
+ EXT_RET int (^d)();
+ EXT_RET ObjCTy *e;
+ EXT_RET __strong ObjCTy *f;
+
+ e = 0; // expected-error{{variable declared with 'objc_externally_retained' cannot be modified in ARC}}
+ f = 0; // expected-error{{variable declared with 'objc_externally_retained' cannot be modified in ARC}}
+ d = ^{ return 0; }; // expected-error{{variable declared with 'objc_externally_retained' cannot be modified in ARC}}
+}
+
+void test2(ObjCTy *a);
+
+void test2(EXT_RET ObjCTy *a) {
+ a = 0; // expected-error{{variable declared with 'objc_externally_retained' cannot be modified in ARC}}
+}
+
+EXT_RET ObjCTy *test3; // expected-warning{{'objc_externally_retained' can only be applied to}}
+
+@interface X // expected-warning{{defined without specifying a base class}} expected-note{{add a super class}}
+-(void)m: (ObjCTy *) p;
+@end
+@implementation X
+-(void)m: (ObjCTy *) EXT_RET p {
+ p = 0; // expected-error{{variable declared with 'objc_externally_retained' cannot be modified in ARC}}
+}
+@end
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -94,6 +94,7 @@
// CHECK-NEXT: ObjCBridgeRelated (SubjectMatchRule_record)
// CHECK-NEXT: ObjCException (SubjectMatchRule_objc_interface)
// CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol)
+// CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable)
// CHECK-NEXT: ObjCMethodFamily (SubjectMatchRule_objc_method)
// CHECK-NEXT: ObjCPreciseLifetime (SubjectMatchRule_variable)
// CHECK-NEXT: ObjCRequiresPropertyDefs (SubjectMatchRule_objc_interface)
Index: clang/test/CodeGenObjC/externally-retained.m
===================================================================
--- /dev/null
+++ clang/test/CodeGenObjC/externally-retained.m
@@ -0,0 +1,121 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -fobjc-arc -fblocks -O0 %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -fobjc-arc -fblocks -O0 -xobjective-c++ -std=c++11 %s -S -emit-llvm -o - | FileCheck %s --check-prefix CHECKXX
+
+#define EXT_RET __attribute__((objc_externally_retained))
+
+@interface ObjTy @end
+
+ObjTy *global;
+
+#if __cplusplus
+// Suppress name mangling in C++ mode for the sake of check lines.
+extern "C" void param(ObjTy *p);
+extern "C" void local();
+extern "C" void in_init();
+extern "C" void anchor();
+extern "C" void block_capture();
+extern "C" void esc(void (^)());
+extern "C" void escp(void (^)(ObjTy *));
+extern "C" void block_param();
+#endif
+
+void param(EXT_RET ObjTy *p) {
+ // CHECK-LABEL: define void @param
+ // CHECK-NOT: llvm.objc.
+ // CHECK ret
+}
+
+void local() {
+ EXT_RET ObjTy *local = global;
+ // CHECK-LABEL: define void @local
+ // CHECK-NOT: llvm.objc.
+ // CHECK: ret
+}
+
+void in_init() {
+ // Test that we do the right thing when a variable appears in it's own
+ // initializer. Here, we release the value stored in 'wat' after overwriting
+ // it, in case it was somehow set to point to a non-null object while it's
+ // initializer is being evaluated.
+ EXT_RET ObjTy *wat = 0 ? wat : global;
+
+ // CHECK-LABEL: define void @in_init
+ // CHECK: [[WAT:%.*]] = alloca
+ // CHECK-NEXT: store {{.*}} null, {{.*}} [[WAT]]
+ // CHECK-NEXT: [[GLOBAL:%.*]] = load {{.*}} @global
+ // CHECK-NEXT: [[WAT_LOAD:%.*]] = load {{.*}} [[WAT]]
+ // CHECK-NEXT: store {{.*}} [[GLOBAL]], {{.*}} [[WAT]]
+ // CHECK-NEXT: [[CASTED:%.*]] = bitcast {{.*}} [[WAT_LOAD]] to
+ // CHECK-NEXT: call void @llvm.objc.release(i8* [[CASTED]])
+
+ // CHECK-NOT: llvm.objc.
+ // CHECK: ret
+}
+
+void esc(void (^)());
+
+void block_capture(EXT_RET ObjTy *obj) {
+ esc(^{ (void)obj; });
+
+ // CHECK-LABEL: define void @block_capture
+ // CHECK-NOT: llvm.objc.
+ // CHECK: call i8* @llvm.objc.retain
+ // CHECK-NOT: llvm.objc.
+ // CHECK: call void @esc
+ // CHECK-NOT: llvm.objc.
+ // CHECK: call void @llvm.objc.storeStrong({{.*}} null)
+ // CHECK-NOT: llvm.objc.
+ // CHECK: ret
+
+ // CHECK-LABEL: define {{.*}} void @__copy_helper_block_
+ // CHECK-NOT: llvm.objc.
+ // CHECK: llvm.objc.storeStrong
+ // CHECK-NOT: llvm.objc.
+ // CHECK: ret
+
+ // CHECK-LABEL: define {{.*}} void @__destroy_helper_block_
+ // CHECK-NOT: llvm.objc.
+ // CHECK: llvm.objc.storeStrong({{.*}} null)
+ // CHECK-NOT: llvm.objc.
+ // CHECK: ret
+}
+
+void escp(void (^)(ObjTy *));
+
+void block_param() {
+ escp(^(EXT_RET ObjTy *p) {});
+
+ // CHECK-LABEL: define internal void @__block_param_block_invoke
+ // CHECK-NOT: llvm.objc.
+ // CHECK: ret
+}
+
+@interface Inter
+-(void)m1: (ObjTy *)w;
+@end
+
+@implementation Inter
+-(void)m1: (ObjTy *) EXT_RET w {
+ // CHECK-LABEL: define internal void @"\01-[Inter m1:]"
+ // CHECK-NOT: llvm.objc.
+ // CHECK: ret
+}
+-(void)m2: (__strong ObjTy *) EXT_RET w {
+ // CHECK-LABEL: define internal void @"\01-[Inter m2:]"
+ // CHECK-NOT: llvm.objc.
+ // CHECK: ret
+}
+@end
+
+#if __cplusplus
+// Verify that the implicit "const" doesn't make it into the name mangling in
+// C++ mode.
+int takes_p(ObjTy *p);
+int call_it = takes_p(0);
+int takes_p(EXT_RET ObjTy *p) {
+ return 0;
+}
+
+// CHECKXX-NOT: _Z7takes_pPK5ObjTy
+// CHECKXX: _Z7takes_pP5ObjTy
+#endif
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -922,13 +922,13 @@
Record.push_back(D->getStorageClass());
Record.push_back(D->getTSCSpec());
Record.push_back(D->getInitStyle());
+ Record.push_back(D->isARCPseudoStrong());
if (!isa<ParmVarDecl>(D)) {
Record.push_back(D->isThisDeclarationADemotedDefinition());
Record.push_back(D->isExceptionVariable());
Record.push_back(D->isNRVOVariable());
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isObjCForDecl());
- Record.push_back(D->isARCPseudoStrong());
Record.push_back(D->isInline());
Record.push_back(D->isInlineSpecified());
Record.push_back(D->isConstexpr());
@@ -1986,6 +1986,7 @@
Abv->Add(BitCodeAbbrevOp(0)); // SClass
Abv->Add(BitCodeAbbrevOp(0)); // TSCSpec
Abv->Add(BitCodeAbbrevOp(0)); // InitStyle
+ Abv->Add(BitCodeAbbrevOp(0)); // ARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // Linkage
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
@@ -2062,12 +2063,12 @@
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // SClass
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // TSCSpec
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // InitStyle
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsThisDeclarationADemotedDefinition
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isObjCForDecl
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // isInline
Abv->Add(BitCodeAbbrevOp(0)); // isInlineSpecified
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1350,6 +1350,7 @@
VD->VarDeclBits.SClass = (StorageClass)Record.readInt();
VD->VarDeclBits.TSCSpec = Record.readInt();
VD->VarDeclBits.InitStyle = Record.readInt();
+ VD->VarDeclBits.ARCPseudoStrong = Record.readInt();
if (!isa<ParmVarDecl>(VD)) {
VD->NonParmVarDeclBits.IsThisDeclarationADemotedDefinition =
Record.readInt();
@@ -1357,7 +1358,6 @@
VD->NonParmVarDeclBits.NRVOVariable = Record.readInt();
VD->NonParmVarDeclBits.CXXForRangeDecl = Record.readInt();
VD->NonParmVarDeclBits.ObjCForDecl = Record.readInt();
- VD->NonParmVarDeclBits.ARCPseudoStrong = Record.readInt();
VD->NonParmVarDeclBits.IsInline = Record.readInt();
VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt();
VD->NonParmVarDeclBits.IsConstexpr = Record.readInt();
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -11215,17 +11215,22 @@
if (var->isARCPseudoStrong() &&
(!var->getTypeSourceInfo() ||
!var->getTypeSourceInfo()->getType().isConstQualified())) {
- // There are two pseudo-strong cases:
+ // There are three pseudo-strong cases:
// - self
ObjCMethodDecl *method = S.getCurMethodDecl();
- if (method && var == method->getSelfDecl())
+ if (method && var == method->getSelfDecl()) {
DiagID = method->isClassMethod()
? diag::err_typecheck_arc_assign_self_class_method
: diag::err_typecheck_arc_assign_self;
+ // - Objective-C externally_retained attribute.
+ } else if (var->hasAttr<ObjCExternallyRetainedAttr>()) {
+ DiagID = diag::err_typecheck_arc_assign_externally_retained;
+
// - fast enumeration variables
- else
+ } else {
DiagID = diag::err_typecheck_arr_assign_enumeration;
+ }
SourceRange Assign;
if (Loc != OrigLoc)
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -6093,6 +6093,43 @@
UninitializedAttr(AL.getLoc(), S.Context, Index));
}
+static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ auto *VD = cast<VarDecl>(D);
+ QualType Ty = VD->getType();
+
+ if (!Ty->isObjCRetainableType() || !VD->isLocalVarDeclOrParm()) {
+ S.Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained);
+ return;
+ }
+
+ 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) {
+ S.Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained);
+ return;
+ }
+
+ // FIXME: If D is explicitly __strong, and this attribute is being applied via
+ // #pragma clang attribute, then ignore this attribute.
+
+ // 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);
+
+ handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -6788,6 +6825,10 @@
case ParsedAttr::AT_Uninitialized:
handleUninitializedAttr(S, D, AL);
break;
+
+ case ParsedAttr::AT_ObjCExternallyRetained:
+ handleObjCExternallyRetainedAttr(S, D, AL);
+ break;
}
}
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -3438,10 +3438,13 @@
RValue EmitLoadOfBitfieldLValue(LValue LV, SourceLocation Loc);
RValue EmitLoadOfGlobalRegLValue(LValue LV);
- /// EmitStoreThroughLValue - Store the specified rvalue into the specified
- /// lvalue, where both are guaranteed to the have the same type, and that type
- /// is 'Ty'.
- void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit = false);
+ /// Store the specified rvalue into the specified lvalue, where both are
+ /// guaranteed to the have the same type.
+ ///
+ /// \param isPsuedoStrong Currently this is always false, but it should be set
+ /// to true if a caller is initializing a pseudo-strong variable.
+ void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit = false,
+ bool isPseudoStrong = false);
void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
void EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst);
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -419,8 +419,12 @@
EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
const Expr *E = M->GetTemporaryExpr();
- // FIXME: ideally this would use EmitAnyExprToMem, however, we cannot do so
- // as that will cause the lifetime adjustment to be lost for ARC
+ assert((!M->getExtendingDecl() || !isa<VarDecl>(M->getExtendingDecl()) ||
+ !cast<VarDecl>(M->getExtendingDecl())->isARCPseudoStrong()) &&
+ "Reference should never be pseudo-strong!");
+
+ // FIXME: ideally this would use EmitAnyExprToMem, however, we cannot do so
+ // as that will cause the lifetime adjustment to be lost for ARC
auto ownership = M->getType().getObjCLifetime();
if (ownership != Qualifiers::OCL_None &&
ownership != Qualifiers::OCL_ExplicitNone) {
@@ -1904,11 +1908,14 @@
}
-/// EmitStoreThroughLValue - Store the specified rvalue into the specified
-/// lvalue, where both are guaranteed to the have the same type, and that type
-/// is 'Ty'.
+/// Store the specified rvalue into the specified lvalue, where both are
+/// guaranteed to the have the same type.
+///
+/// \param isPsuedoStrong Currently this is always false, but it should be set
+/// to true if a caller is initializing a pseudo-strong variable.
void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
- bool isInit) {
+ bool isInit,
+ bool isPseudoStrong) {
if (!Dst.isSimple()) {
if (Dst.isVectorElt()) {
// Read/modify/write the vector, inserting the new element.
@@ -1935,6 +1942,9 @@
// There's special magic for assigning into an ARC-qualified l-value.
if (Qualifiers::ObjCLifetime Lifetime = Dst.getQuals().getObjCLifetime()) {
+ if (isInit && isPseudoStrong)
+ Lifetime = Qualifiers::OCL_ExplicitNone;
+
switch (Lifetime) {
case Qualifiers::OCL_None:
llvm_unreachable("present but none");
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -797,15 +797,19 @@
case Qualifiers::OCL_None:
llvm_unreachable("present but none");
+ case Qualifiers::OCL_Strong: {
+ if (!D || !isa<VarDecl>(D) || !cast<VarDecl>(D)->isARCPseudoStrong()) {
+ value = EmitARCRetainScalarExpr(init);
+ break;
+ }
+ // If D is pseudo-strong, omit the retain.
+ LLVM_FALLTHROUGH;
+ }
+
case Qualifiers::OCL_ExplicitNone:
value = EmitARCUnsafeUnretainedScalarExpr(init);
break;
- case Qualifiers::OCL_Strong: {
- value = EmitARCRetainScalarExpr(init);
- break;
- }
-
case Qualifiers::OCL_Weak: {
// If it's not accessed by the initializer, try to emit the
// initialization with a copy or move.
@@ -2326,16 +2330,20 @@
// 'self' is always formally __strong, but if this is not an
// init method then we don't want to retain it.
- if (D.isARCPseudoStrong()) {
- const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CurCodeDecl);
- assert(&D == method->getSelfDecl());
- assert(lt == Qualifiers::OCL_Strong);
- assert(qs.hasConst());
- assert(method->getMethodFamily() != OMF_init);
- (void) method;
- lt = Qualifiers::OCL_ExplicitNone;
+ if (auto *Method = dyn_cast<ObjCMethodDecl>(CurCodeDecl)) {
+ if (D.isARCPseudoStrong() && Method->getSelfDecl() == &D) {
+ assert(lt == Qualifiers::OCL_Strong);
+ assert(qs.hasConst());
+ assert(Method->getMethodFamily() != OMF_init);
+ lt = Qualifiers::OCL_ExplicitNone;
+ }
}
+ // If a parameter is pseudo-strong (due to 'objc_externally_retained'),
+ // then we omit the implicit retain.
+ if (D.isARCPseudoStrong())
+ lt = Qualifiers::OCL_ExplicitNone;
+
// Load objects passed indirectly.
if (Arg.isIndirect() && !ArgVal)
ArgVal = Builder.CreateLoad(DeclPtr);
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3488,6 +3488,11 @@
def err_objc_attr_protocol_requires_definition : Error<
"attribute %0 can only be applied to @protocol definitions, not forward declarations">;
+def warn_ignored_objc_externally_retained : Warning<
+ "'objc_externally_retained' can only be applied to local variables or "
+ "parameters of strong, retainable object pointer type">,
+ InGroup<IgnoredAttributes>;
+
// Function Parameter Semantic Analysis.
def err_param_with_void_type : Error<"argument may not have 'void' type">;
def err_void_only_param : Error<
@@ -5261,6 +5266,9 @@
def err_typecheck_arr_assign_enumeration : Error<
"fast enumeration variables cannot be modified in ARC by default; "
"declare the variable __strong to allow this">;
+def err_typecheck_arc_assign_externally_retained : Error<
+ "variable declared with 'objc_externally_retained' "
+ "cannot be modified in ARC">;
def warn_arc_retained_assign : Warning<
"assigning retained object to %select{weak|unsafe_unretained}0 "
"%select{property|variable}1"
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -3774,3 +3774,21 @@
(even after inlining) end up hardened.
}];
}
+
+def ObjCExternallyRetainedDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+The ``objc_externally_retained`` attribute can be applied to strong function
+parameters or local variables in ARC mode. When applied to parameters, it causes
+clang to omit the implicit calls to objc_retain and objc_release on function
+entry and exit respectivly. When applied to local variables, it causes clang to
+omit the call to retain on variable initialization, and release when the
+variable goes out of scope. Parameters and variables annotated with this
+attribute are implicitly ``const``.
+
+This attribute is meant to be used to opt-out of the additional safety that ARC
+provides when the programmer knows that the safety isn't necessary. You can read
+more about ARC `here
+<https://clang.llvm.org/docs/AutomaticReferenceCounting.html>`_.
+ }];
+}
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -300,6 +300,7 @@
def RenderScript : LangOpt<"RenderScript">;
def ObjC : LangOpt<"ObjC">;
def BlocksSupported : LangOpt<"Blocks">;
+def ObjCAutoRefCount : LangOpt<"ObjCAutoRefCount">;
// Defines targets for target-specific attributes. Empty lists are unchecked.
class TargetSpec {
@@ -3137,3 +3138,10 @@
let Subjects = SubjectList<[LocalVar]>;
let Documentation = [UninitializedDocs];
}
+
+def ObjCExternallyRetained : InheritableParamAttr {
+ let LangOpts = [ObjCAutoRefCount];
+ let Spellings = [Clang<"objc_externally_retained">];
+ let Subjects = SubjectList<[Var]>;
+ let Documentation = [ObjCExternallyRetainedDocs];
+}
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -866,8 +866,12 @@
unsigned SClass : 3;
unsigned TSCSpec : 2;
unsigned InitStyle : 2;
+
+ /// Whether this variable is an ARC pseudo-__strong variable; see
+ /// isARCPseudoStrong() for details.
+ unsigned ARCPseudoStrong : 1;
};
- enum { NumVarDeclBits = 7 };
+ enum { NumVarDeclBits = 8 };
protected:
enum { NumParameterIndexBits = 8 };
@@ -940,10 +944,6 @@
/// Whether this variable is the for-in loop declaration in Objective-C.
unsigned ObjCForDecl : 1;
- /// Whether this variable is an ARC pseudo-__strong
- /// variable; see isARCPseudoStrong() for details.
- unsigned ARCPseudoStrong : 1;
-
/// Whether this variable is (C++1z) inline.
unsigned IsInline : 1;
@@ -1349,17 +1349,12 @@
NonParmVarDeclBits.ObjCForDecl = FRD;
}
- /// Determine whether this variable is an ARC pseudo-__strong
- /// variable. A pseudo-__strong variable has a __strong-qualified
- /// type but does not actually retain the object written into it.
- /// Generally such variables are also 'const' for safety.
- bool isARCPseudoStrong() const {
- return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.ARCPseudoStrong;
- }
- void setARCPseudoStrong(bool ps) {
- assert(!isa<ParmVarDecl>(this));
- NonParmVarDeclBits.ARCPseudoStrong = ps;
- }
+ /// Determine whether this variable is an ARC pseudo-__strong variable. A
+ /// pseudo-__strong variable has a __strong-qualified type but does not
+ /// actually retain the object written into it. Generally such variables are
+ /// also 'const' for safety.
+ bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; }
+ void setARCPseudoStrong(bool PS) { VarDeclBits.ARCPseudoStrong = PS; }
/// Whether this variable is (C++1z) inline.
bool isInline() const {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits