diff options
author | John McCall <rjmccall@apple.com> | 2015-10-22 18:38:17 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2015-10-22 18:38:17 +0000 |
commit | 460ce58fa6a165ebad98c848aaec2f09cefe7603 (patch) | |
tree | 9520b5118e8d8cc7cbe1449609c40f3b9ec7b11b /clang/lib | |
parent | 63d23d1b127e43cff2b287b371fdbf6e0a6d83f0 (diff) | |
download | bcm5719-llvm-460ce58fa6a165ebad98c848aaec2f09cefe7603.tar.gz bcm5719-llvm-460ce58fa6a165ebad98c848aaec2f09cefe7603.zip |
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
llvm-svn: 251041
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/ARCMigrate/ARCMT.cpp | 3 | ||||
-rw-r--r-- | clang/lib/ARCMigrate/Transforms.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Basic/Targets.cpp | 14 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGBlocks.cpp | 69 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 31 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 5 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 32 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjCMac.cpp | 123 | ||||
-rw-r--r-- | clang/lib/Driver/Tools.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Frontend/InitPreprocessor.cpp | 48 | ||||
-rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCast.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaObjCProperty.cpp | 82 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 43 |
20 files changed, 330 insertions, 179 deletions
diff --git a/clang/lib/ARCMigrate/ARCMT.cpp b/clang/lib/ARCMigrate/ARCMT.cpp index 7eb01fb93db..82d8acd87e8 100644 --- a/clang/lib/ARCMigrate/ARCMT.cpp +++ b/clang/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/clang/lib/ARCMigrate/Transforms.cpp b/clang/lib/ARCMigrate/Transforms.cpp index 56d3af7233b..99cfacb63dc 100644 --- a/clang/lib/ARCMigrate/Transforms.cpp +++ b/clang/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/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 94e3e7ca29b..e774e115344 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/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/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 01b10082047..e3d8602b695 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/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/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index cfb09e72c7b..3f7256b9271 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/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/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f61f63470c7..cc3516185ce 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/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<llvm::GlobalVariable>(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<CXXPseudoDestructorExpr>(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/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index ae4e02d53f0..71e4b98986b 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/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/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 5890e7fc9b4..fce74095148 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/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<CastExpr>(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/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index a44cdf8c345..44c9a90c76c 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/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<RecordType>()) { + 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<llvm::Constant*> 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/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 74a49580b0b..4c23a2961ce 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/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/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 71ee7e47149..99963bab09c 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/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/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index dc075793ac8..3d62d88917b 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -323,15 +323,17 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, Out << "template<typename _Tp> struct __is_scalar;\n" << "\n"; + + if (LangOpts.ObjCAutoRefCount) { + Out << "template<typename _Tp>\n" + << "struct __is_scalar<__attribute__((objc_ownership(strong))) _Tp> {\n" + << " enum { __value = 0 };\n" + << " typedef __false_type __type;\n" + << "};\n" + << "\n"; + } - Out << "template<typename _Tp>\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<typename _Tp>\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<typename _Tp>\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<typename _Tp>\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/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 3e834289f6c..98b79637201 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/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/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index e2136ac27bd..94ec7961d3e 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/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/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 5099867b199..4aecd08d9fe 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/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/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 84936745b9a..06d9e375db8 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 047ff152cf8..f9e75893bf3 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 1b43f92128e..badb2ef118f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1702,7 +1702,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, MarkDeclRefReferenced(E); - if (getLangOpts().ObjCARCWeak && isa<VarDecl>(D) && + if (getLangOpts().ObjCWeak && isa<VarDecl>(D) && Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart())) recordUseOfEvaluatedWeak(E); diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 374e5ccd918..04465958c1c 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/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<ObjCObjectPointerType>()) { + 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<ObjCObjectPointerType>()) { - 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/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d1bf6cc6bb2..e53c7792e50 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/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<ObjCObjectPointerType>()) { 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); } } } |