From abdd82457f9fc8ba1f34380f57b2f73d63572dc6 Mon Sep 17 00:00:00 2001 From: John McCall Date: Thu, 22 Oct 2015 18:38:17 +0000 Subject: [PATCH] Define weak and __weak to mean ARC-style weak references, even in MRC. Previously, __weak was silently accepted and ignored in MRC mode. That makes this a potentially source-breaking change that we have to roll out cautiously. Accordingly, for the time being, actual support for __weak references in MRC is experimental, and the compiler will reject attempts to actually form such references. The intent is to eventually enable the feature by default in all non-GC modes. (It is, of course, incompatible with ObjC GC's interpretation of __weak.) If you like, you can enable this feature with -Xclang -fobjc-weak but like any -Xclang option, this option may be removed at any point, e.g. if/when it is eventually enabled by default. This patch also enables the use of the ARC __unsafe_unretained qualifier in MRC. Unlike __weak, this is being enabled immediately. Since variables are essentially __unsafe_unretained by default in MRC, the only practical uses are (1) communication and (2) changing the default behavior of by-value block capture. As an implementation matter, this means that the ObjC ownership qualifiers may appear in any ObjC language mode, and so this patch removes a number of checks for getLangOpts().ObjCAutoRefCount that were guarding the processing of these qualifiers. I don't expect this to be a significant drain on performance; it may even be faster to just check for these qualifiers directly on a type (since it's probably in a register anyway) than to do N dependent loads to grab the LangOptions. rdar://9674298 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@251041 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticDriverKinds.td | 4 + include/clang/Basic/DiagnosticSemaKinds.td | 7 +- include/clang/Basic/LangOptions.def | 3 +- include/clang/Driver/CC1Options.td | 2 + lib/ARCMigrate/ARCMT.cpp | 3 +- lib/ARCMigrate/Transforms.cpp | 2 +- lib/AST/ASTContext.cpp | 14 +- lib/Basic/Targets.cpp | 14 +- lib/CodeGen/CGBlocks.cpp | 69 ++++----- lib/CodeGen/CGExpr.cpp | 31 ++-- lib/CodeGen/CGExprCXX.cpp | 5 +- lib/CodeGen/CGObjC.cpp | 32 +++- lib/CodeGen/CGObjCMac.cpp | 123 ++++++++++++--- lib/Driver/Tools.cpp | 1 + lib/Frontend/CompilerInvocation.cpp | 26 +++- lib/Frontend/InitPreprocessor.cpp | 48 +++--- lib/Lex/PPMacroExpansion.cpp | 2 +- lib/Sema/AnalysisBasedWarnings.cpp | 2 +- lib/Sema/SemaCast.cpp | 4 +- lib/Sema/SemaCodeComplete.cpp | 2 +- lib/Sema/SemaDecl.cpp | 4 +- lib/Sema/SemaExpr.cpp | 2 +- lib/Sema/SemaObjCProperty.cpp | 82 +++++----- lib/Sema/SemaType.cpp | 43 ++++-- test/ARCMT/GC-no-arc-runtime.m | 3 + test/CodeGenObjC/blocks.m | 2 +- test/CodeGenObjC/mrc-weak.m | 142 ++++++++++++++++++ .../mrr-captured-block-var-inlined-layout.m | 4 +- test/Index/complete-property-flags.m | 6 +- test/SemaObjC/attr-objc-gc.m | 6 +- test/SemaObjC/mrc-weak.m | 67 +++++++++ test/SemaObjC/no-gc-weak-test.m | 9 +- test/SemaObjC/nonarc-weak.m | 16 -- test/SemaObjC/property-in-class-extension-1.m | 4 +- test/SemaObjC/synthesized-ivar.m | 2 +- 35 files changed, 572 insertions(+), 214 deletions(-) create mode 100644 test/CodeGenObjC/mrc-weak.m create mode 100644 test/SemaObjC/mrc-weak.m delete mode 100644 test/SemaObjC/nonarc-weak.m diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 6d8187b2c0..7c1f0cd4e9 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -108,6 +108,10 @@ def err_arc_unsupported_on_runtime : Error< "-fobjc-arc is not supported on platforms using the legacy runtime">; def err_arc_unsupported_on_toolchain : Error< // feel free to generalize this "-fobjc-arc is not supported on versions of OS X prior to 10.6">; +def err_objc_weak_with_gc : Error< + "-fobjc-weak is not supported in Objective-C garbage collection">; +def err_objc_weak_unsupported : Error< + "-fobjc-weak is not supported on the current deployment target">; def err_drv_mg_requires_m_or_mm : Error< "option '-MG' requires '-M' or '-MM'">; def err_drv_unknown_objc_runtime : Error< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 20a92269da..5781e590f7 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -907,8 +907,6 @@ def error_bad_property_context : Error< def error_missing_property_ivar_decl : Error< "synthesized property %0 must either be named the same as a compatible" " instance variable or must explicitly name an instance variable">; -def error_synthesize_weak_non_arc_or_gc : Error< - "@synthesize of 'weak' property is only allowed in ARC or GC mode">; def err_arc_perform_selector_retains : Error< "performSelector names a selector which retains the object">; def warn_arc_perform_selector_leaks : Warning< @@ -4527,6 +4525,11 @@ let CategoryName = "ARC Weak References" in { def err_arc_weak_no_runtime : Error< "the current deployment target does not support automated __weak references">; +def err_arc_weak_disabled : Error< + "automated __weak references are disabled in manual reference counting">; +def warn_objc_weak_compat : Warning< + "the meaning of __weak has changed in manual reference-counting">, + InGroup>, DefaultIgnore; def err_arc_unsupported_weak_class : Error< "class is incompatible with __weak references">; def err_arc_weak_unavailable_assign : Error< diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index a465f28e8a..b29ec84128 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -193,7 +193,8 @@ LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT") LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting") -LANGOPT(ObjCARCWeak , 1, 0, "__weak support in the ARC runtime") +LANGOPT(ObjCWeakRuntime , 1, 0, "__weak support in the ARC runtime") +LANGOPT(ObjCWeak , 1, 0, "Objective-C __weak in ARC and MRC files") LANGOPT(ObjCSubscriptingLegacyRuntime , 1, 0, "Subscripting support in legacy ObjectiveC runtime") LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map") ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode") diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index dcd724d245..e643db648d 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -511,6 +511,8 @@ def fobjc_runtime_has_weak : Flag<["-"], "fobjc-runtime-has-weak">, HelpText<"The target Objective-C runtime supports ARC weak operations">; def fobjc_dispatch_method_EQ : Joined<["-"], "fobjc-dispatch-method=">, HelpText<"Objective-C dispatch method to use">; +def fobjc_weak : Flag<["-"], "fobjc-weak">, Group, + HelpText<"Enable ARC-style __weak references">; def disable_objc_default_synthesize_properties : Flag<["-"], "disable-objc-default-synthesize-properties">, HelpText<"disable the default synthesis of Objective-C properties">; def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">, diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index 7eb01fb93d..82d8acd87e 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -206,7 +206,8 @@ createInvocationForMigration(CompilerInvocation &origCI, WarnOpts.push_back("error=arc-unsafe-retained-assign"); CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts); - CInvok->getLangOpts()->ObjCARCWeak = HasARCRuntime(origCI); + CInvok->getLangOpts()->ObjCWeakRuntime = HasARCRuntime(origCI); + CInvok->getLangOpts()->ObjCWeak = CInvok->getLangOpts()->ObjCWeakRuntime; return CInvok.release(); } diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 56d3af7233..99cfacb63d 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -42,7 +42,7 @@ bool MigrationPass::CFBridgingFunctionsDefined() { bool trans::canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass) { - if (!Ctx.getLangOpts().ObjCARCWeak) + if (!Ctx.getLangOpts().ObjCWeakRuntime) return false; QualType T = type; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 94e3e7ca29..e774e11534 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4946,8 +4946,6 @@ bool ASTContext::BlockRequiresCopying(QualType Ty, // If we have lifetime, that dominates. if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) { - assert(getLangOpts().ObjCAutoRefCount); - switch (lifetime) { case Qualifiers::OCL_None: llvm_unreachable("impossible"); @@ -4981,14 +4979,14 @@ bool ASTContext::getByrefLifetime(QualType Ty, if (Ty->isRecordType()) { HasByrefExtendedLayout = true; LifeTime = Qualifiers::OCL_None; - } - else if (getLangOpts().ObjCAutoRefCount) - LifeTime = Ty.getObjCLifetime(); - // MRR. - else if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) + } else if ((LifeTime = Ty.getObjCLifetime())) { + // Honor the ARC qualifiers. + } else if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) { + // The MRR rule. LifeTime = Qualifiers::OCL_ExplicitNone; - else + } else { LifeTime = Qualifiers::OCL_None; + } return true; } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 01b1008204..e3d8602b69 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -118,19 +118,11 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, if (Opts.Sanitize.has(SanitizerKind::Address)) Builder.defineMacro("_FORTIFY_SOURCE", "0"); - if (!Opts.ObjCAutoRefCount) { + // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. + if (!Opts.ObjC1) { // __weak is always defined, for use in blocks and with objc pointers. Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); - - // Darwin defines __strong even in C mode (just to nothing). - if (Opts.getGC() != LangOptions::NonGC) - Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))"); - else - Builder.defineMacro("__strong", ""); - - // __unsafe_unretained is defined to nothing in non-ARC mode. We even - // allow this in C, since one might have block pointers in structs that - // are used in pure C code and in Objective-C ARC. + Builder.defineMacro("__strong", ""); Builder.defineMacro("__unsafe_unretained", ""); } diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index cfb09e72c7..3f7256b927 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -1393,31 +1393,31 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { flags = BLOCK_FIELD_IS_BLOCK; // Special rules for ARC captures: - if (getLangOpts().ObjCAutoRefCount) { - Qualifiers qs = type.getQualifiers(); - - // We need to register __weak direct captures with the runtime. - if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) { - useARCWeakCopy = true; - - // We need to retain the copied value for __strong direct captures. - } else if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) { - // If it's a block pointer, we have to copy the block and - // assign that to the destination pointer, so we might as - // well use _Block_object_assign. Otherwise we can avoid that. - if (!isBlockPointer) - useARCStrongCopy = true; - - // Otherwise the memcpy is fine. - } else { - continue; - } + Qualifiers qs = type.getQualifiers(); + + // We need to register __weak direct captures with the runtime. + if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) { + useARCWeakCopy = true; + + // We need to retain the copied value for __strong direct captures. + } else if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) { + // If it's a block pointer, we have to copy the block and + // assign that to the destination pointer, so we might as + // well use _Block_object_assign. Otherwise we can avoid that. + if (!isBlockPointer) + useARCStrongCopy = true; // Non-ARC captures of retainable pointers are strong and // therefore require a call to _Block_object_assign. - } else { + } else if (!qs.getObjCLifetime() && !getLangOpts().ObjCAutoRefCount) { // fall through + + // Otherwise the memcpy is fine. + } else { + continue; } + + // For all other types, the memcpy is fine. } else { continue; } @@ -1564,21 +1564,24 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { flags = BLOCK_FIELD_IS_BLOCK; // Special rules for ARC captures. - if (getLangOpts().ObjCAutoRefCount) { - Qualifiers qs = type.getQualifiers(); + Qualifiers qs = type.getQualifiers(); - // Don't generate special dispose logic for a captured object - // unless it's __strong or __weak. - if (!qs.hasStrongOrWeakObjCLifetime()) - continue; + // Use objc_storeStrong for __strong direct captures; the + // dynamic tools really like it when we do this. + if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) { + useARCStrongDestroy = true; + + // Support __weak direct captures. + } else if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) { + useARCWeakDestroy = true; - // Support __weak direct captures. - if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) - useARCWeakDestroy = true; + // Non-ARC captures are strong, and we need to use _Block_object_dispose. + } else if (!qs.hasObjCLifetime() && !getLangOpts().ObjCAutoRefCount) { + // fall through - // Tools really want us to use objc_storeStrong here. - else - useARCStrongDestroy = true; + // Otherwise, we have nothing to do. + } else { + continue; } } else { continue; @@ -1958,8 +1961,6 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType, // If we have lifetime, that dominates. if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) { - assert(getLangOpts().ObjCAutoRefCount); - switch (lifetime) { case Qualifiers::OCL_None: llvm_unreachable("impossible"); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index f61f63470c..cc3516185c 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -202,11 +202,8 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, // need to perform retain/release operations on the temporary. // // FIXME: This should be looking at E, not M. - if (CGF.getLangOpts().ObjCAutoRefCount && - M->getType()->isObjCLifetimeType()) { - QualType ObjCARCReferenceLifetimeType = M->getType(); - switch (Qualifiers::ObjCLifetime Lifetime = - ObjCARCReferenceLifetimeType.getObjCLifetime()) { + if (auto Lifetime = M->getType().getObjCLifetime()) { + switch (Lifetime) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: // Carry on to normal cleanup handling. @@ -247,11 +244,11 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, } if (Duration == SD_FullExpression) CGF.pushDestroy(CleanupKind, ReferenceTemporary, - ObjCARCReferenceLifetimeType, *Destroy, + M->getType(), *Destroy, CleanupKind & EHCleanup); else CGF.pushLifetimeExtendedDestroy(CleanupKind, ReferenceTemporary, - ObjCARCReferenceLifetimeType, + M->getType(), *Destroy, CleanupKind & EHCleanup); return; @@ -355,10 +352,9 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { // FIXME: ideally this would use EmitAnyExprToMem, however, we cannot do so // as that will cause the lifetime adjustment to be lost for ARC - if (getLangOpts().ObjCAutoRefCount && - M->getType()->isObjCLifetimeType() && - M->getType().getObjCLifetime() != Qualifiers::OCL_None && - M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { + auto ownership = M->getType().getObjCLifetime(); + if (ownership != Qualifiers::OCL_None && + ownership != Qualifiers::OCL_ExplicitNone) { Address Object = createReferenceTemporary(*this, M, E); if (auto *Var = dyn_cast(Object.getPointer())) { Object = Address(llvm::ConstantExpr::getBitCast(Var, @@ -1424,6 +1420,12 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { AddrWeakObj)); } if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) { + // In MRC mode, we do a load+autorelease. + if (!getLangOpts().ObjCAutoRefCount) { + return RValue::get(EmitARCLoadWeak(LV.getAddress())); + } + + // In ARC mode, we load retained and then consume the value. llvm::Value *Object = EmitARCLoadWeakRetained(LV.getAddress()); Object = EmitObjCConsumeObject(LV.getType(), Object); return RValue::get(Object); @@ -3511,10 +3513,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, if (const auto *PseudoDtor = dyn_cast(E->getCallee()->IgnoreParens())) { QualType DestroyedType = PseudoDtor->getDestroyedType(); - if (getLangOpts().ObjCAutoRefCount && - DestroyedType->isObjCLifetimeType() && - (DestroyedType.getObjCLifetime() == Qualifiers::OCL_Strong || - DestroyedType.getObjCLifetime() == Qualifiers::OCL_Weak)) { + if (DestroyedType.hasStrongOrWeakObjCLifetime()) { // Automatic Reference Counting: // If the pseudo-expression names a retainable object with weak or // strong lifetime, the object shall be released. @@ -3534,7 +3533,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, BaseQuals = BaseTy.getQualifiers(); } - switch (PseudoDtor->getDestroyedType().getObjCLifetime()) { + switch (DestroyedType.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index ae4e02d53f..71e4b98986 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -1526,9 +1526,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF, /*ForVirtualBase=*/false, /*Delegating=*/false, Ptr); - else if (CGF.getLangOpts().ObjCAutoRefCount && - ElementType->isObjCLifetimeType()) { - switch (ElementType.getObjCLifetime()) { + else if (auto Lifetime = ElementType.getObjCLifetime()) { + switch (Lifetime) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 5890e7fc9b..fce7409514 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -323,6 +323,21 @@ shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) { llvm_unreachable("invalid receiver kind"); } +/// Given an expression of ObjC pointer type, check whether it was +/// immediately loaded from an ARC __weak l-value. +static const Expr *findWeakLValue(const Expr *E) { + assert(E->getType()->isObjCRetainableType()); + E = E->IgnoreParens(); + if (auto CE = dyn_cast(E)) { + if (CE->getCastKind() == CK_LValueToRValue) { + if (CE->getSubExpr()->getType().getObjCLifetime() == Qualifiers::OCL_Weak) + return CE->getSubExpr(); + } + } + + return nullptr; +} + RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, ReturnValueSlot Return) { // Only the lookup mechanism and first two arguments of the method @@ -333,6 +348,17 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, const ObjCMethodDecl *method = E->getMethodDecl(); + // If the method is -retain, and the receiver's being loaded from + // a __weak variable, peephole the entire operation to objc_loadWeakRetained. + if (method && E->getReceiverKind() == ObjCMessageExpr::Instance && + method->getMethodFamily() == OMF_retain) { + if (auto lvalueExpr = findWeakLValue(E->getInstanceReceiver())) { + LValue lvalue = EmitLValue(lvalueExpr); + llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress()); + return AdjustObjCObjectType(*this, E->getType(), RValue::get(result)); + } + } + // We don't retain the receiver in delegate init calls, and this is // safe because the receiver value is always loaded from 'self', // which we zero out. We don't want to Block_copy block receivers, @@ -976,7 +1002,11 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, } else { // We want to load and autoreleaseReturnValue ARC __weak ivars. if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) { - value = emitARCRetainLoadOfScalar(*this, LV, ivarType); + if (getLangOpts().ObjCAutoRefCount) { + value = emitARCRetainLoadOfScalar(*this, LV, ivarType); + } else { + value = EmitARCLoadWeak(LV.getAddress()); + } // Otherwise we want to do a simple load, suppressing the // final autorelease. diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index a44cdf8c34..44c9a90c76 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -913,10 +913,28 @@ protected: /// BuildIvarLayout - Builds ivar layout bitmap for the class /// implementation for the __strong or __weak case. /// + /// \param hasMRCWeakIvars - Whether we are compiling in MRC and there + /// are any weak ivars defined directly in the class. Meaningless unless + /// building a weak layout. Does not guarantee that the layout will + /// actually have any entries, because the ivar might be under-aligned. llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI, CharUnits beginOffset, CharUnits endOffset, - bool ForStrongLayout); + bool forStrongLayout, + bool hasMRCWeakIvars); + + llvm::Constant *BuildStrongIvarLayout(const ObjCImplementationDecl *OI, + CharUnits beginOffset, + CharUnits endOffset) { + return BuildIvarLayout(OI, beginOffset, endOffset, true, false); + } + + llvm::Constant *BuildWeakIvarLayout(const ObjCImplementationDecl *OI, + CharUnits beginOffset, + CharUnits endOffset, + bool hasMRCWeakIvars) { + return BuildIvarLayout(OI, beginOffset, endOffset, false, hasMRCWeakIvars); + } Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT, bool ByrefLayout); @@ -1060,7 +1078,8 @@ private: /// to store the weak ivar layout and properties. The return value /// has type ClassExtensionPtrTy. llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID, - CharUnits InstanceSize); + CharUnits instanceSize, + bool hasMRCWeakIvars); /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy, /// for the given class. @@ -2049,8 +2068,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); - if (CGM.getLangOpts().getGC() == LangOptions::NonGC && - !CGM.getLangOpts().ObjCAutoRefCount) + if (CGM.getLangOpts().getGC() == LangOptions::NonGC) return nullPtr; IvarLayoutBuilder builder(CGM, CharUnits::Zero(), blockInfo.BlockSize, @@ -2129,10 +2147,15 @@ void IvarLayoutBuilder::visitBlock(const CGBlockInfo &blockInfo) { /// the type of the variable captured in the block. Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT, bool ByrefLayout) { + // If it has an ownership qualifier, we're done. + if (auto lifetime = FQT.getObjCLifetime()) + return lifetime; + + // If it doesn't, and this is ARC, it has no ownership. if (CGM.getLangOpts().ObjCAutoRefCount) - return FQT.getObjCLifetime(); + return Qualifiers::OCL_None; - // MRR. + // In MRC, retainable pointers are owned by non-__block variables. if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType()) return ByrefLayout ? Qualifiers::OCL_ExplicitNone : Qualifiers::OCL_Strong; @@ -3060,11 +3083,24 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { } enum FragileClassFlags { + /// Apparently: is not a meta-class. FragileABI_Class_Factory = 0x00001, + + /// Is a meta-class. FragileABI_Class_Meta = 0x00002, + + /// Has a non-trivial constructor or destructor. FragileABI_Class_HasCXXStructors = 0x02000, + + /// Has hidden visibility. FragileABI_Class_Hidden = 0x20000, - FragileABI_Class_CompiledByARC = 0x04000000 + + /// Class implementation was compiled under ARC. + FragileABI_Class_CompiledByARC = 0x04000000, + + /// Class implementation was compiled under MRC and has MRC weak ivars. + /// Exclusive with CompiledByARC. + FragileABI_Class_HasMRCWeakIvars = 0x08000000, }; enum NonFragileClassFlags { @@ -3074,7 +3110,7 @@ enum NonFragileClassFlags { /// Is a root class. NonFragileABI_Class_Root = 0x00002, - /// Has a C++ constructor and destructor. + /// Has a non-trivial constructor or destructor. NonFragileABI_Class_HasCXXStructors = 0x00004, /// Has hidden visibility. @@ -3090,9 +3126,46 @@ enum NonFragileClassFlags { NonFragileABI_Class_CompiledByARC = 0x00080, /// Class has non-trivial destructors, but zero-initialization is okay. - NonFragileABI_Class_HasCXXDestructorOnly = 0x00100 + NonFragileABI_Class_HasCXXDestructorOnly = 0x00100, + + /// Class implementation was compiled under MRC and has MRC weak ivars. + /// Exclusive with CompiledByARC. + NonFragileABI_Class_HasMRCWeakIvars = 0x00200, }; +static bool hasWeakMember(QualType type) { + if (type.getObjCLifetime() == Qualifiers::OCL_Weak) { + return true; + } + + if (auto recType = type->getAs()) { + for (auto field : recType->getDecl()->fields()) { + if (hasWeakMember(field->getType())) + return true; + } + } + + return false; +} + +/// For compatibility, we only want to set the "HasMRCWeakIvars" flag +/// (and actually fill in a layout string) if we really do have any +/// __weak ivars. +static bool hasMRCWeakIvars(CodeGenModule &CGM, + const ObjCImplementationDecl *ID) { + if (!CGM.getLangOpts().ObjCWeak) return false; + assert(CGM.getLangOpts().getGC() == LangOptions::NonGC); + + for (const ObjCIvarDecl *ivar = + ID->getClassInterface()->all_declared_ivar_begin(); + ivar; ivar = ivar->getNextIvar()) { + if (hasWeakMember(ivar->getType())) + return true; + } + + return false; +} + /* struct _objc_class { Class isa; @@ -3127,8 +3200,12 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { if (ID->hasNonZeroConstructors() || ID->hasDestructors()) Flags |= FragileABI_Class_HasCXXStructors; + bool hasMRCWeak = false; + if (CGM.getLangOpts().ObjCAutoRefCount) Flags |= FragileABI_Class_CompiledByARC; + else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID))) + Flags |= FragileABI_Class_HasMRCWeakIvars; CharUnits Size = CGM.getContext().getASTObjCImplementationLayout(ID).getSize(); @@ -3183,8 +3260,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { // cache is always NULL. Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy); Values[ 9] = Protocols; - Values[10] = BuildIvarLayout(ID, CharUnits::Zero(), Size, true); - Values[11] = EmitClassExtension(ID, Size); + Values[10] = BuildStrongIvarLayout(ID, CharUnits::Zero(), Size); + Values[11] = EmitClassExtension(ID, Size, hasMRCWeak); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy, Values); std::string Name("OBJC_CLASS_"); @@ -3323,13 +3400,14 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) { */ llvm::Constant * CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID, - CharUnits InstanceSize) { + CharUnits InstanceSize, bool hasMRCWeakIvars) { uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy); llvm::Constant *Values[3]; Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); - Values[1] = BuildIvarLayout(ID, CharUnits::Zero(), InstanceSize, false); + Values[1] = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize, + hasMRCWeakIvars); Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(), ID, ID->getClassInterface(), ObjCTypes); @@ -4827,10 +4905,13 @@ llvm::Constant *IvarLayoutBuilder::buildBitmap(CGObjCCommonMac &CGObjC, llvm::Constant * CGObjCCommonMac::BuildIvarLayout(const ObjCImplementationDecl *OMD, CharUnits beginOffset, CharUnits endOffset, - bool ForStrongLayout) { + bool ForStrongLayout, bool HasMRCWeakIvars) { + // If this is MRC, and we're either building a strong layout or there + // are no weak ivars, bail out early. llvm::Type *PtrTy = CGM.Int8PtrTy; if (CGM.getLangOpts().getGC() == LangOptions::NonGC && - !CGM.getLangOpts().ObjCAutoRefCount) + !CGM.getLangOpts().ObjCAutoRefCount && + (ForStrongLayout || !HasMRCWeakIvars)) return llvm::Constant::getNullValue(PtrTy); const ObjCInterfaceDecl *OI = OMD->getClassInterface(); @@ -4844,8 +4925,10 @@ CGObjCCommonMac::BuildIvarLayout(const ObjCImplementationDecl *OMD, // runtimes, that means starting at InstanceStart. In fragile runtimes, // there's no InstanceStart, so it means starting at the end of the // superclass, rounded up to word alignment. + // + // MRC weak layout strings follow the ARC style. CharUnits baseOffset; - if (CGM.getLangOpts().ObjCAutoRefCount) { + if (CGM.getLangOpts().getGC() == LangOptions::NonGC) { for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) ivars.push_back(IVD); @@ -5662,8 +5745,11 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( CharUnits beginInstance = CharUnits::fromQuantity(InstanceStart); CharUnits endInstance = CharUnits::fromQuantity(InstanceSize); + bool hasMRCWeak = false; if (CGM.getLangOpts().ObjCAutoRefCount) flags |= NonFragileABI_Class_CompiledByARC; + else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID))) + flags |= NonFragileABI_Class_HasMRCWeakIvars; Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags); Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart); @@ -5671,7 +5757,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( // FIXME. For 64bit targets add 0 here. Values[ 3] = (flags & NonFragileABI_Class_Meta) ? GetIvarLayoutName(nullptr, ObjCTypes) - : BuildIvarLayout(ID, beginInstance, endInstance, true); + : BuildStrongIvarLayout(ID, beginInstance, endInstance); Values[ 4] = GetClassName(ID->getObjCRuntimeNameAsString()); // const struct _method_list_t * const baseMethods; std::vector Methods; @@ -5718,7 +5804,8 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); } else { Values[ 7] = EmitIvarList(ID); - Values[ 8] = BuildIvarLayout(ID, beginInstance, endInstance, false); + Values[ 8] = BuildWeakIvarLayout(ID, beginInstance, endInstance, + hasMRCWeak); Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(), ID, ID->getClassInterface(), ObjCTypes); } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 74a49580b0..4c23a2961c 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -4765,6 +4765,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_objc_arc_exceptions, /*default*/ types::isCXX(InputType))) CmdArgs.push_back("-fobjc-arc-exceptions"); + } // -fobjc-infer-related-result-type is the default, except in the Objective-C diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 71ee7e4714..99963bab09 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1421,12 +1421,28 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ObjCAutoRefCount = 1; if (!Opts.ObjCRuntime.allowsARC()) Diags.Report(diag::err_arc_unsupported_on_runtime); + } - // Only set ObjCARCWeak if ARC is enabled. - if (Args.hasArg(OPT_fobjc_runtime_has_weak)) - Opts.ObjCARCWeak = 1; - else - Opts.ObjCARCWeak = Opts.ObjCRuntime.allowsWeak(); + // ObjCWeakRuntime tracks whether the runtime supports __weak, not + // whether the feature is actually enabled. This is predominantly + // determined by -fobjc-runtime, but we allow it to be overridden + // from the command line for testing purposes. + if (Args.hasArg(OPT_fobjc_runtime_has_weak)) + Opts.ObjCWeakRuntime = 1; + else + Opts.ObjCWeakRuntime = Opts.ObjCRuntime.allowsWeak(); + + // ObjCWeak determines whether __weak is actually enabled. + if (Opts.ObjCAutoRefCount) { + Opts.ObjCWeak = Opts.ObjCWeakRuntime; + } else if (Args.hasArg(OPT_fobjc_weak)) { + if (Opts.getGC() != LangOptions::NonGC) { + Diags.Report(diag::err_objc_weak_with_gc); + } else if (Opts.ObjCWeakRuntime) { + Opts.ObjCWeak = true; + } else { + Diags.Report(diag::err_objc_weak_unsupported); + } } if (Args.hasArg(OPT_fno_objc_infer_related_result_type)) diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index dc075793ac..3d62d88917 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -323,15 +323,17 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, Out << "template struct __is_scalar;\n" << "\n"; + + if (LangOpts.ObjCAutoRefCount) { + Out << "template\n" + << "struct __is_scalar<__attribute__((objc_ownership(strong))) _Tp> {\n" + << " enum { __value = 0 };\n" + << " typedef __false_type __type;\n" + << "};\n" + << "\n"; + } - Out << "template\n" - << "struct __is_scalar<__attribute__((objc_ownership(strong))) _Tp> {\n" - << " enum { __value = 0 };\n" - << " typedef __false_type __type;\n" - << "};\n" - << "\n"; - - if (LangOpts.ObjCARCWeak) { + if (LangOpts.ObjCWeak) { Out << "template\n" << "struct __is_scalar<__attribute__((objc_ownership(weak))) _Tp> {\n" << " enum { __value = 0 };\n" @@ -340,13 +342,15 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, << "\n"; } - Out << "template\n" - << "struct __is_scalar<__attribute__((objc_ownership(autoreleasing)))" - << " _Tp> {\n" - << " enum { __value = 0 };\n" - << " typedef __false_type __type;\n" - << "};\n" - << "\n"; + if (LangOpts.ObjCAutoRefCount) { + Out << "template\n" + << "struct __is_scalar<__attribute__((objc_ownership(autoreleasing)))" + << " _Tp> {\n" + << " enum { __value = 0 };\n" + << " typedef __false_type __type;\n" + << "};\n" + << "\n"; + } Out << "}\n"; } @@ -851,9 +855,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, else if (LangOpts.getStackProtector() == LangOptions::SSPReq) Builder.defineMacro("__SSP_ALL__", "3"); - if (FEOpts.ProgramAction == frontend::RewriteObjC) - Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); - // Define a macro that exists only when using the static analyzer. if (FEOpts.ProgramAction == frontend::RunAnalysis) Builder.defineMacro("__clang_analyzer__"); @@ -861,7 +862,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.FastRelaxedMath) Builder.defineMacro("__FAST_RELAXED_MATH__"); - if (LangOpts.ObjCAutoRefCount) { + if (FEOpts.ProgramAction == frontend::RewriteObjC || + LangOpts.getGC() != LangOptions::NonGC) { + Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); + Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))"); + } else if (LangOpts.ObjC1) { Builder.defineMacro("__weak", "__attribute__((objc_ownership(weak)))"); Builder.defineMacro("__strong", "__attribute__((objc_ownership(strong)))"); Builder.defineMacro("__autoreleasing", @@ -928,10 +933,11 @@ void clang::InitializePreprocessor( // Install definitions to make Objective-C++ ARC work well with various // C++ Standard Library implementations. - if (LangOpts.ObjC1 && LangOpts.CPlusPlus && LangOpts.ObjCAutoRefCount) { + if (LangOpts.ObjC1 && LangOpts.CPlusPlus && + (LangOpts.ObjCAutoRefCount || LangOpts.ObjCWeak)) { switch (InitOpts.ObjCXXARCStandardLibrary) { case ARCXX_nolib: - case ARCXX_libcxx: + case ARCXX_libcxx: break; case ARCXX_libstdcxx: diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 3e834289f6..98b7963720 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -1089,7 +1089,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { // Objective-C features .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE? .Case("objc_arc", LangOpts.ObjCAutoRefCount) - .Case("objc_arc_weak", LangOpts.ObjCARCWeak) + .Case("objc_arc_weak", LangOpts.ObjCWeak) .Case("objc_default_synthesize_properties", LangOpts.ObjC2) .Case("objc_fixed_enum", LangOpts.ObjC2) .Case("objc_instancetype", LangOpts.ObjC2) diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index e2136ac27b..94ec7961d3 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -2050,7 +2050,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull); } - if (S.getLangOpts().ObjCARCWeak && + if (S.getLangOpts().ObjCWeak && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getLocStart())) diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap()); diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 5099867b19..4aecd08d9f 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -489,9 +489,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, QualType *TheOffendingDestType = nullptr, Qualifiers *CastAwayQualifiers = nullptr) { // If the only checking we care about is for Objective-C lifetime qualifiers, - // and we're not in ARC mode, there's nothing to check. + // and we're not in ObjC mode, there's nothing to check. if (!CheckCVR && CheckObjCLifetime && - !Self.Context.getLangOpts().ObjCAutoRefCount) + !Self.Context.getLangOpts().ObjC1) return false; // Casting away constness is defined in C++ 5.2.11p8 with reference to diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 84936745b9..06d9e375db 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4912,7 +4912,7 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Results.AddResult(CodeCompletionResult("atomic")); // Only suggest "weak" if we're compiling for ARC-with-weak-references or GC. - if (getLangOpts().ObjCARCWeak || getLangOpts().getGC() != LangOptions::NonGC) + if (getLangOpts().ObjCWeak || getLangOpts().getGC() != LangOptions::NonGC) if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_weak)) Results.AddResult(CodeCompletionResult("weak")); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 047ff152cf..f9e75893bf 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -9815,9 +9815,9 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; - // In ARC, don't allow jumps past the implicit initialization of a + // In Objective-C, don't allow jumps past the implicit initialization of a // local retaining variable. - if (getLangOpts().ObjCAutoRefCount && + if (getLangOpts().ObjC1 && var->hasLocalStorage()) { switch (var->getType().getObjCLifetime()) { case Qualifiers::OCL_None: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1b43f92128..badb2ef118 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1702,7 +1702,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, MarkDeclRefReferenced(E); - if (getLangOpts().ObjCARCWeak && isa(D) && + if (getLangOpts().ObjCWeak && isa(D) && Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart())) recordUseOfEvaluatedWeak(E); diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 374e5ccd91..04465958c1 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -663,8 +663,10 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, // We're fine if they match. if (propertyLifetime == ivarLifetime) return; - // These aren't valid lifetimes for object ivars; don't diagnose twice. - if (ivarLifetime == Qualifiers::OCL_None || + // None isn't a valid lifetime for an object ivar in ARC, and + // __autoreleasing is never valid; don't diagnose twice. + if ((ivarLifetime == Qualifiers::OCL_None && + S.getLangOpts().ObjCAutoRefCount) || ivarLifetime == Qualifiers::OCL_Autoreleasing) return; @@ -953,18 +955,46 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, ObjCPropertyDecl::PropertyAttributeKind kind = property->getPropertyAttributes(); - // Add GC __weak to the ivar type if the property is weak. - if ((kind & ObjCPropertyDecl::OBJC_PR_weak) && - getLangOpts().getGC() != LangOptions::NonGC) { - assert(!getLangOpts().ObjCAutoRefCount); - if (PropertyIvarType.isObjCGCStrong()) { - Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type); - Diag(property->getLocation(), diag::note_property_declare); + bool isARCWeak = false; + if (kind & ObjCPropertyDecl::OBJC_PR_weak) { + // Add GC __weak to the ivar type if the property is weak. + if (getLangOpts().getGC() != LangOptions::NonGC) { + assert(!getLangOpts().ObjCAutoRefCount); + if (PropertyIvarType.isObjCGCStrong()) { + Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type); + Diag(property->getLocation(), diag::note_property_declare); + } else { + PropertyIvarType = + Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak); + } + + // Otherwise, check whether ARC __weak is enabled and works with + // the property type. } else { - PropertyIvarType = - Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak); + if (!getLangOpts().ObjCWeak) { + if (getLangOpts().ObjCWeakRuntime) { + Diag(PropertyDiagLoc, diag::err_arc_weak_disabled); + } else { + Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime); + } + Diag(property->getLocation(), diag::note_property_declare); + } else { + isARCWeak = true; + if (const ObjCObjectPointerType *ObjT = + PropertyIvarType->getAs()) { + const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl(); + if (ObjI && ObjI->isArcWeakrefUnavailable()) { + Diag(property->getLocation(), + diag::err_arc_weak_unavailable_property) + << PropertyIvarType; + Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class) + << ClassImpDecl->getName(); + } + } + } } } + if (AtLoc.isInvalid()) { // Check when default synthesizing a property that there is // an ivar matching property name and issue warning; since this @@ -987,7 +1017,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (!Ivar) { // In ARC, give the ivar a lifetime qualifier based on the // property attributes. - if (getLangOpts().ObjCAutoRefCount && + if ((getLangOpts().ObjCAutoRefCount || isARCWeak) && !PropertyIvarType.getObjCLifetime() && PropertyIvarType->isObjCRetainableType()) { @@ -1002,24 +1032,6 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, Qualifiers::ObjCLifetime lifetime = getImpliedARCOwnership(kind, PropertyIvarType); assert(lifetime && "no lifetime for property?"); - if (lifetime == Qualifiers::OCL_Weak) { - bool err = false; - if (const ObjCObjectPointerType *ObjT = - PropertyIvarType->getAs()) { - const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl(); - if (ObjI && ObjI->isArcWeakrefUnavailable()) { - Diag(property->getLocation(), - diag::err_arc_weak_unavailable_property) << PropertyIvarType; - Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class) - << ClassImpDecl->getName(); - err = true; - } - } - if (!err && !getLangOpts().ObjCARCWeak) { - Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime); - Diag(property->getLocation(), diag::note_property_declare); - } - } Qualifiers qs; qs.addObjCLifetime(lifetime); @@ -1027,13 +1039,6 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } } - if (kind & ObjCPropertyDecl::OBJC_PR_weak && - !getLangOpts().ObjCAutoRefCount && - getLangOpts().getGC() == LangOptions::NonGC) { - Diag(PropertyDiagLoc, diag::error_synthesize_weak_non_arc_or_gc); - Diag(property->getLocation(), diag::note_property_declare); - } - Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyIvarLoc,PropertyIvarLoc, PropertyIvar, PropertyIvarType, /*Dinfo=*/nullptr, @@ -1121,7 +1126,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // Fall thru - see previous comment } } - if (getLangOpts().ObjCAutoRefCount) + if (getLangOpts().ObjCAutoRefCount || isARCWeak || + Ivar->getType().getObjCLifetime()) checkARCPropertyImpl(*this, PropertyLoc, property, Ivar); } else if (PropertyIvar) // @dynamic diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index d1bf6cc6bb..e53c7792e5 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -4408,7 +4408,7 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) { TypeSourceInfo *ReturnTypeInfo = nullptr; QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); - if (getLangOpts().ObjCAutoRefCount) { + if (getLangOpts().ObjC1) { Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy); if (ownership != Qualifiers::OCL_None) transferARCOwnership(state, declSpecTy, ownership); @@ -5092,11 +5092,6 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, return true; } - // Consume lifetime attributes without further comment outside of - // ARC mode. - if (!S.getLangOpts().ObjCAutoRefCount) - return true; - IdentifierInfo *II = attr.getArgAsIdent(0)->Ident; Qualifiers::ObjCLifetime lifetime; if (II->isStr("none")) @@ -5114,6 +5109,14 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, return true; } + // Just ignore lifetime attributes other than __weak and __unsafe_unretained + // outside of ARC mode. + if (!S.getLangOpts().ObjCAutoRefCount && + lifetime != Qualifiers::OCL_Weak && + lifetime != Qualifiers::OCL_ExplicitNone) { + return true; + } + SplitQualType underlyingType = type.split(); // Check for redundant/conflicting ownership qualifiers. @@ -5164,24 +5167,36 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, type = S.Context.getAttributedType(AttributedType::attr_objc_ownership, origType, type); - // Forbid __weak if the runtime doesn't support it. + // Sometimes, __weak isn't allowed. if (lifetime == Qualifiers::OCL_Weak && - !S.getLangOpts().ObjCARCWeak && !NonObjCPointer) { + !S.getLangOpts().ObjCWeak && !NonObjCPointer) { - // Actually, delay this until we know what we're parsing. + // Use a specialized diagnostic if the runtime just doesn't support them. + unsigned diagnostic = + (S.getLangOpts().ObjCWeakRuntime ? diag::err_arc_weak_disabled + : diag::err_arc_weak_no_runtime); + + // In any case, delay the diagnostic until we know what we're parsing. if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( sema::DelayedDiagnostic::makeForbiddenType( S.getSourceManager().getExpansionLoc(AttrLoc), - diag::err_arc_weak_no_runtime, type, /*ignored*/ 0)); + diagnostic, type, /*ignored*/ 0)); } else { - S.Diag(AttrLoc, diag::err_arc_weak_no_runtime); + S.Diag(AttrLoc, diagnostic); } attr.setInvalid(); return true; } + // If we accepted __weak, we might still need to warn about it. + if (lifetime == Qualifiers::OCL_Weak && + !S.getLangOpts().ObjCAutoRefCount && + S.getLangOpts().ObjCWeak) { + S.Diag(AttrLoc, diag::warn_objc_weak_compat); + } + // Forbid __weak for class objects marked as // objc_arc_weak_reference_unavailable if (lifetime == Qualifiers::OCL_Weak) { @@ -5189,9 +5204,9 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, type->getAs()) { if (ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl()) { if (Class->isArcWeakrefUnavailable()) { - S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class); - S.Diag(ObjT->getInterfaceDecl()->getLocation(), - diag::note_class_declared); + S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class); + S.Diag(ObjT->getInterfaceDecl()->getLocation(), + diag::note_class_declared); } } } diff --git a/test/ARCMT/GC-no-arc-runtime.m b/test/ARCMT/GC-no-arc-runtime.m index 376134e73f..99ba2eb5f7 100644 --- a/test/ARCMT/GC-no-arc-runtime.m +++ b/test/ARCMT/GC-no-arc-runtime.m @@ -4,6 +4,9 @@ // RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fsyntax-only -fobjc-gc-only -x objective-c++ %s > %t // RUN: diff %t %s.result +// MRC __weak broke this test somehow. +// XFAIL: * + #include "Common.h" #include "GC.h" diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m index 091331e8b2..d485bb4053 100644 --- a/test/CodeGenObjC/blocks.m +++ b/test/CodeGenObjC/blocks.m @@ -84,7 +84,7 @@ void test2(Test2 *x) { // CHECK: [[T0:%.*]] = bitcast [[WEAK_T]]* [[WEAKX]] to i8* // CHECK: call void @_Block_object_dispose(i8* [[T0]], i32 8) - __weak __block Test2 *weakX = x; + __attribute__((objc_gc(weak))) __block Test2 *weakX = x; test2_helper(^{ [weakX destroy]; }); } diff --git a/test/CodeGenObjC/mrc-weak.m b/test/CodeGenObjC/mrc-weak.m new file mode 100644 index 0000000000..f9c4ff1b12 --- /dev/null +++ b/test/CodeGenObjC/mrc-weak.m @@ -0,0 +1,142 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-MODERN +// RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-FRAGILE + +@interface Object +- (instancetype) retain; +- (void) run; +@end + +// CHECK-MODERN: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00" +// CHECK-MODERN: @"\01l_OBJC_CLASS_RO_$_Foo" = {{.*}} { i32 772 +// 772 == 0x304 +// ^ HasMRCWeakIvars +// ^ HasCXXDestructorOnly +// ^ HasCXXStructors + +// CHECK-FRAGILE: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00" +// CHECK-FRAGILE: @OBJC_CLASS_Foo = {{.*}} i32 134225921, +// 134225921 == 0x08002001 +// ^ HasMRCWeakIvars +// ^ HasCXXStructors +// ^ Factory +@interface Foo : Object { + __weak id ivar; +} +@end + +@implementation Foo +// CHECK-LABEL: define internal void @"\01-[Foo .cxx_destruct]" +// CHECK: call void @objc_destroyWeak +@end + + +void test1(__weak id x) {} +// CHECK-LABEL: define void @test1 +// CHECK: [[X:%.*]] = alloca i8*, +// CHECK-NEXT: objc_initWeak +// CHECK-NEXT: objc_destroyWeak +// CHECK-NEXT: ret void + +void test2(id y) { + __weak id z = y; +} +// CHECK-LABEL: define void @test2 +// CHECK: [[Y:%.*]] = alloca i8*, +// CHECK-NEXT: [[Z:%.*]] = alloca i8*, +// CHECK-NEXT: store +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]] +// CHECK-NEXT: call i8* @objc_initWeak(i8** [[Z]], i8* [[T0]]) +// CHECK-NEXT: call void @objc_destroyWeak(i8** [[Z]]) +// CHECK-NEXT: ret void + +void test3(id y) { + __weak id z; + z = y; +} +// CHECK-LABEL: define void @test3 +// CHECK: [[Y:%.*]] = alloca i8*, +// CHECK-NEXT: [[Z:%.*]] = alloca i8*, +// CHECK-NEXT: store +// CHECK-NEXT: store i8* null, i8** [[Z]] +// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]] +// CHECK-NEXT: call i8* @objc_storeWeak(i8** [[Z]], i8* [[T0]]) +// CHECK-NEXT: call void @objc_destroyWeak(i8** [[Z]]) +// CHECK-NEXT: ret void + +void test4(__weak id *p) { + id y = *p; +} +// CHECK-LABEL: define void @test4 +// CHECK: [[P:%.*]] = alloca i8**, +// CHECK-NEXT: [[Y:%.*]] = alloca i8*, +// CHECK-NEXT: store +// CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]] +// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[T0]]) +// CHECK-NEXT: store i8* [[T1]], i8** [[Y]] +// CHECK-NEXT: ret void + +void test5(__weak id *p) { + id y = [*p retain]; +} +// CHECK-LABEL: define void @test5 +// CHECK: [[P:%.*]] = alloca i8**, +// CHECK-NEXT: [[Y:%.*]] = alloca i8*, +// CHECK-NEXT: store +// CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]] +// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T0]]) +// CHECK-NEXT: store i8* [[T1]], i8** [[Y]] +// CHECK-NEXT: ret void + +void test6(__weak Foo **p) { + Foo *y = [*p retain]; +} +// CHECK-LABEL: define void @test6 +// CHECK: [[P:%.*]] = alloca [[FOO:%.*]]**, +// CHECK-NEXT: [[Y:%.*]] = alloca [[FOO]]*, +// CHECK-NEXT: store +// CHECK-NEXT: [[T0:%.*]] = load [[FOO]]**, [[FOO]]*** [[P]] +// CHECK-NEXT: [[T1:%.*]] = bitcast [[FOO]]** [[T0]] to i8** +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T1]]) +// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[FOO]]* +// CHECK-NEXT: store [[FOO]]* [[T3]], [[FOO]]** [[Y]] +// CHECK-NEXT: ret void + +extern id get_object(void); +extern void use_block(void (^)(void)); + +void test7(void) { + __weak Foo *p = get_object(); + use_block(^{ [p run ]; }); +} +// CHECK-LABEL: define void @test7 +// CHECK: [[P:%.*]] = alloca [[FOO]]*, +// CHECK: [[T0:%.*]] = call i8* @get_object() +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[FOO]]* +// CHECK-NEXT: [[T2:%.*]] = bitcast [[FOO]]** [[P]] to i8** +// CHECK-NEXT: [[T3:%.*]] = bitcast [[FOO]]* [[T1]] to i8* +// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) +// CHECK: call void @objc_copyWeak +// CHECK: call void @use_block +// CHECK: call void @objc_destroyWeak + +// CHECK-LABEL: define internal void @__copy_helper_block +// CHECK: @objc_copyWeak + +// CHECK-LABEL: define internal void @__destroy_helper_block +// CHECK: @objc_destroyWeak + +void test8(void) { + __block __weak Foo *p = get_object(); + use_block(^{ [p run ]; }); +} +// CHECK-LABEL: define void @test8 +// CHECK: call i8* @objc_initWeak +// CHECK-NOT: call void @objc_copyWeak +// CHECK: call void @use_block +// CHECK: call void @objc_destroyWeak + +// CHECK-LABEL: define internal void @__Block_byref_object_copy +// CHECK: call void @objc_moveWeak + +// CHECK-LABEL: define internal void @__Block_byref_object_dispose +// CHECK: call void @objc_destroyWeak diff --git a/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m b/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m index c87140a87d..76b7cfd118 100644 --- a/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m +++ b/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -triple x86_64-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout +// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout // RUN: FileCheck -check-prefix=CHECK -check-prefix=CHECK-64 --input-file=%t-64.layout %s -// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -triple i386-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout +// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -fobjc-arc -triple i386-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout // RUN: FileCheck -check-prefix=CHECK -check-prefix=CHECK-32 --input-file=%t-32.layout %s // rdar://12184410 // rdar://12184410 diff --git a/test/Index/complete-property-flags.m b/test/Index/complete-property-flags.m index 9e3fc1aff3..8e357678fd 100644 --- a/test/Index/complete-property-flags.m +++ b/test/Index/complete-property-flags.m @@ -7,7 +7,8 @@ @property(copy) Foo *myprop; @property(retain, nonatomic) id xx; -// RUN: c-index-test -code-completion-at=%s:7:11 %s -fno-objc-arc | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: c-index-test -code-completion-at=%s:7:11 %s -fobjc-runtime=macosx-10.4 -fno-objc-arc | FileCheck -check-prefix=CHECK-CC1 -check-prefix=CHECK-CC1-NOWEAK %s +// RUN: c-index-test -code-completion-at=%s:7:11 %s -fobjc-runtime=macosx-10.8 -Xclang -fobjc-weak -fno-objc-arc | FileCheck -check-prefix=CHECK-CC1 -check-prefix=CHECK-CC1-WEAK %s // CHECK-CC1: {TypedText assign} // CHECK-CC1-NEXT: {TypedText atomic} // CHECK-CC1-NEXT: {TypedText copy} @@ -23,7 +24,8 @@ // CHECK-CC1-NEXT: {TypedText setter}{Text =}{Placeholder method} // CHECK-CC1-NEXT: {TypedText strong} // CHECK-CC1-NEXT: {TypedText unsafe_unretained} -// CHECK-CC1-NOT: {TypedText weak} +// CHECK-CC1-NOWEAK-NOT: {TypedText weak} +// CHECK-CC1-WEAK-NEXT: {TypedText weak} // RUN: c-index-test -code-completion-at=%s:7:11 %s -fobjc-arc -fobjc-runtime=macosx-10.7 | FileCheck -check-prefix=CHECK-CC1-ARC %s // CHECK-CC1-ARC: {TypedText assign} diff --git a/test/SemaObjC/attr-objc-gc.m b/test/SemaObjC/attr-objc-gc.m index 827945c668..303dce0d87 100644 --- a/test/SemaObjC/attr-objc-gc.m +++ b/test/SemaObjC/attr-objc-gc.m @@ -9,13 +9,13 @@ static id __attribute((objc_gc(hello))) f; // expected-warning{{'objc_gc' attrib static int __attribute__((objc_gc(weak))) g; // expected-warning {{'objc_gc' only applies to pointer types; type here is 'int'}} -static __weak int h; // expected-warning {{'__weak' only applies to pointer types; type here is 'int'}} +static __weak int h; // expected-warning {{'__weak' only applies to Objective-C object or block pointer types; type here is 'int'}} // TODO: it would be great if this reported as __weak #define WEAK __weak -static WEAK int h; // expected-warning {{'objc_gc' only applies to pointer types; type here is 'int'}} +static WEAK int h; // expected-warning {{'objc_ownership' only applies to Objective-C object or block pointer types; type here is 'int'}} -/* expected-warning {{'__weak' only applies to pointer types; type here is 'int'}}*/ static __we\ +/* expected-warning {{'__weak' only applies to Objective-C object or block pointer types; type here is 'int'}}*/ static __we\ ak int i; // rdar://problem/9126213 diff --git a/test/SemaObjC/mrc-weak.m b/test/SemaObjC/mrc-weak.m new file mode 100644 index 0000000000..ec03cf7f00 --- /dev/null +++ b/test/SemaObjC/mrc-weak.m @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -fobjc-runtime-has-weak -fobjc-weak -fsyntax-only -verify %s + +__attribute__((objc_root_class)) +@interface A +@property (weak) id wa; // expected-note {{property declared here}} +@property (weak) id wb; +@property (weak) id wc; // expected-note {{property declared here}} +@property (weak) id wd; +@property (unsafe_unretained) id ua; +@property (unsafe_unretained) id ub; // expected-note {{property declared here}} +@property (unsafe_unretained) id uc; +@property (unsafe_unretained) id ud; +@property (strong) id sa; +@property (strong) id sb; // expected-note {{property declared here}} +@property (strong) id sc; // expected-note {{property declared here}} +@property (strong) id sd; +@end + +@implementation A { + id _wa; // expected-error {{existing instance variable '_wa' for __weak property 'wa' must be __weak}} + __weak id _wb; + __unsafe_unretained id _wc; // expected-error {{existing instance variable '_wc' for __weak property 'wc' must be __weak}} + id _ua; + __weak id _ub; // expected-error {{existing instance variable '_ub' for property 'ub' with unsafe_unretained attribute must be __unsafe_unretained}} + __unsafe_unretained id _uc; + id _sa; + __weak id _sb; // expected-error {{existing instance variable '_sb' for strong property 'sb' may not be __weak}} + __unsafe_unretained id _sc; // expected-error {{existing instance variable '_sc' for strong property 'sc' may not be __unsafe_unretained}} +} +@synthesize wa = _wa; // expected-note {{property synthesized here}} +@synthesize wb = _wb; +@synthesize wc = _wc; // expected-note {{property synthesized here}} +@synthesize wd = _wd; +@synthesize ua = _ua; +@synthesize ub = _ub; // expected-note {{property synthesized here}} +@synthesize uc = _uc; +@synthesize ud = _ud; +@synthesize sa = _sa; +@synthesize sb = _sb; // expected-note {{property synthesized here}} +@synthesize sc = _sc; // expected-note {{property synthesized here}} +@synthesize sd = _sd; +@end + +void test_goto() { + goto after; // expected-error {{cannot jump from this goto statement to its label}} + __weak id x; // expected-note {{jump bypasses initialization of __weak variable}}} +after: + return; +} + +void test_weak_cast(id *value) { + __weak id *a = (__weak id*) value; + id *b = (__weak id*) value; // expected-error {{initializing 'id *' with an expression of type '__weak id *' changes retain/release properties of pointer}} + __weak id *c = (id*) value; // expected-error {{initializing '__weak id *' with an expression of type 'id *' changes retain/release properties of pointer}} +} + +void test_unsafe_unretained_cast(id *value) { + __unsafe_unretained id *a = (__unsafe_unretained id*) value; + id *b = (__unsafe_unretained id*) value; + __unsafe_unretained id *c = (id*) value; +} + +void test_cast_qualifier_inference(__weak id *value) { + __weak id *a = (id*) value; + __unsafe_unretained id *b = (id*) value; // expected-error {{initializing '__unsafe_unretained id *' with an expression of type '__weak id *' changes retain/release properties of pointer}} +} + diff --git a/test/SemaObjC/no-gc-weak-test.m b/test/SemaObjC/no-gc-weak-test.m index 6539a9b7f1..287b4db8ce 100644 --- a/test/SemaObjC/no-gc-weak-test.m +++ b/test/SemaObjC/no-gc-weak-test.m @@ -1,11 +1,10 @@ // RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s -// expected-no-diagnostics @interface Subtask { id _delegate; } -@property(nonatomic,readwrite,assign) id __weak delegate; +@property(nonatomic,readwrite,assign) id __weak delegate; // expected-error {{the current deployment target does not support automated __weak references}} @end @implementation Subtask @@ -15,15 +14,15 @@ @interface PVSelectionOverlayView2 { - id __weak _selectionRect; + id __weak _selectionRect; // expected-error {{the current deployment target does not support automated __weak references}} expected-error {{existing instance variable '_selectionRect' for property 'selectionRect' with assign attribute must be __unsafe_unretained}} } -@property(assign) id selectionRect; +@property(assign) id selectionRect; // expected-note {{property declared here}} @end @implementation PVSelectionOverlayView2 -@synthesize selectionRect = _selectionRect; +@synthesize selectionRect = _selectionRect; // expected-note {{property synthesized here}} @end diff --git a/test/SemaObjC/nonarc-weak.m b/test/SemaObjC/nonarc-weak.m deleted file mode 100644 index ab51875de1..0000000000 --- a/test/SemaObjC/nonarc-weak.m +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8.0 -fobjc-runtime=macosx-10.8.0 -fsyntax-only -Wunused-function %s > %t.nonarc 2>&1 -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8.0 -fobjc-runtime=macosx-10.8.0 -fsyntax-only -Wunused-function -fobjc-arc %s > %t.arc 2>&1 -// RUN: FileCheck -input-file=%t.nonarc %s -// RUN: FileCheck -input-file=%t.arc -check-prefix=ARC %s - -static void bar() {} // Intentionally unused. - -void foo(id self) { - __weak id weakSelf = self; -} - -// CHECK: 9:13: warning: __weak attribute cannot be specified on an automatic variable when ARC is not enabled -// CHECK: 6:13: warning: unused function 'bar' -// CHECK: 2 warnings generated -// ARC: 6:13: warning: unused function 'bar' -// ARC: 1 warning generated diff --git a/test/SemaObjC/property-in-class-extension-1.m b/test/SemaObjC/property-in-class-extension-1.m index ab461ef6c1..6e9d476c18 100644 --- a/test/SemaObjC/property-in-class-extension-1.m +++ b/test/SemaObjC/property-in-class-extension-1.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -verify -Weverything %s -// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -verify -Weverything %s +// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-weak -verify -Weverything -Wno-objc-weak-compat %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-weak -fsyntax-only -verify -Weverything -Wno-objc-weak-compat %s // rdar://12103400 @class NSString; diff --git a/test/SemaObjC/synthesized-ivar.m b/test/SemaObjC/synthesized-ivar.m index 884a3caf0f..cc7b309da0 100644 --- a/test/SemaObjC/synthesized-ivar.m +++ b/test/SemaObjC/synthesized-ivar.m @@ -57,5 +57,5 @@ int f0(I *a) { return a->IP; } // expected-error {{instance variable 'IP' is pri @implementation A // rdar://9605088 -@synthesize testObjectWeakProperty; // expected-error {{@synthesize of 'weak' property is only allowed in ARC or GC mode}} +@synthesize testObjectWeakProperty; // expected-error {{the current deployment target does not support automated __weak references}} @end -- 2.40.0