diff options
| author | John McCall <rjmccall@apple.com> | 2015-10-27 04:54:50 +0000 |
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2015-10-27 04:54:50 +0000 |
| commit | b61e14e5962a2b881db3b7515e8c4f6f762fa0f2 (patch) | |
| tree | 535f9505a6499d7a3da0a52f714fb3699730f527 /clang/lib/Sema | |
| parent | c692688cbd6e1f73426ebf3d660d05677603427d (diff) | |
| download | bcm5719-llvm-b61e14e5962a2b881db3b7515e8c4f6f762fa0f2.tar.gz bcm5719-llvm-b61e14e5962a2b881db3b7515e8c4f6f762fa0f2.zip | |
Be more conservative about diagnosing "incorrect" uses of __weak:
allow them to be written in certain kinds of user declaration and
diagnose on the use-site instead.
Also, improve and fix some diagnostics relating to __weak and
properties.
rdar://23228631
llvm-svn: 251384
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 53 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 18 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaObjCProperty.cpp | 127 |
3 files changed, 138 insertions, 60 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 1f3497609e0..51f9e45d7e2 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5332,26 +5332,53 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { } /// Is the given declaration allowed to use a forbidden type? -static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) { +/// If so, it'll still be annotated with an attribute that makes it +/// illegal to actually use. +static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, + const DelayedDiagnostic &diag, + llvm::StringRef &explanation) { // Private ivars are always okay. Unfortunately, people don't // always properly make their ivars private, even in system headers. // Plus we need to make fields okay, too. - // Function declarations in sys headers will be marked unavailable. if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl) && !isa<FunctionDecl>(decl)) return false; - // Require it to be declared in a system header. - return S.Context.getSourceManager().isInSystemHeader(decl->getLocation()); + // All of these declarations are allowed in all system headers. which + // we assume to not be defined in user code. + if (S.Context.getSourceManager().isInSystemHeader(decl->getLocation())) { + explanation = "this system declaration uses an unsupported type"; + return true; + } + + // We do also need to allow __weak in user declarations when it's been + // disabled, for ease of integration with -fno-objc-arc files, but we + // have to take some care against attempts to define such things. + // For now, that care only extends to ivars and properties. + if ((isa<ObjCIvarDecl>(decl) || isa<ObjCPropertyDecl>(decl))) { + // TODO: find a way to localize these. + if (diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_disabled) { + explanation = "cannot use weak references in file using manual " + "reference counting"; + return true; + } + if (diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_no_runtime) { + explanation = "cannot use weak references because the current " + "deployment target does not support them"; + return true; + } + } + + return false; } /// Handle a delayed forbidden-type diagnostic. static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, Decl *decl) { - if (decl && isForbiddenTypeAllowed(S, decl)) { - decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, - "this system declaration uses an unsupported type", - diag.Loc)); + llvm::StringRef explanation; + if (decl && isForbiddenTypeAllowed(S, decl, diag, explanation)) { + decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, explanation, + diag.Loc)); return; } if (S.getLangOpts().ObjCAutoRefCount) @@ -5404,6 +5431,7 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, bool ObjCPropertyAccess) { // Diagnostics for deprecated or unavailable. unsigned diag, diag_message, diag_fwdclass_message; + unsigned diag_available_here = diag::note_availability_specified_here; // Matches 'diag::note_property_attribute' options. unsigned property_note_select; @@ -5433,6 +5461,13 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, diag_fwdclass_message = diag::warn_unavailable_fwdclass_message; property_note_select = /* unavailable */ 1; available_here_select_kind = /* unavailable */ 0; + + if (!Message.empty()) { + if (auto attr = D->getAttr<UnavailableAttr>()) + if (attr->isImplicit()) + diag_available_here = diag::note_unavailability_inferred_here; + } + break; case Sema::AD_Partial: @@ -5459,7 +5494,7 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } - S.Diag(D->getLocation(), diag::note_availability_specified_here) + S.Diag(D->getLocation(), diag_available_here) << D << available_here_select_kind; if (K == Sema::AD_Partial) S.Diag(Loc, diag::note_partial_availability_silence) << D; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 5b402e5f6ed..dbdb558ba42 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -3495,6 +3495,23 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, } } +/// Diagnose attempts to define ARC-__weak ivars when __weak is disabled. +static void DiagnoseWeakIvars(Sema &S, ObjCImplementationDecl *ID) { + if (S.getLangOpts().ObjCWeak) return; + + for (auto ivar = ID->getClassInterface()->all_declared_ivar_begin(); + ivar; ivar = ivar->getNextIvar()) { + if (ivar->isInvalidDecl()) continue; + if (ivar->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { + if (S.getLangOpts().ObjCWeakRuntime) { + S.Diag(ivar->getLocation(), diag::err_arc_weak_disabled); + } else { + S.Diag(ivar->getLocation(), diag::err_arc_weak_no_runtime); + } + } + } +} + Sema::ObjCContainerKind Sema::getObjCContainerKind() const { switch (CurContext->getDeclKind()) { case Decl::ObjCInterface: @@ -3644,6 +3661,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, DiagnoseUnusedBackingIvarInAccessor(S, IC); if (IDecl->hasDesignatedInitializers()) DiagnoseMissingDesignatedInitOverrides(IC, IDecl); + DiagnoseWeakIvars(*this, IC); bool HasRootClassAttr = IDecl->hasAttr<ObjCRootClassAttr>(); if (IDecl->getSuperClass() == nullptr) { diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 04465958c1c..bd99143d4c9 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -61,8 +61,10 @@ static Qualifiers::ObjCLifetime getImpliedARCOwnership( return Qualifiers::OCL_None; } -/// Check the internal consistency of a property declaration. -static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { +/// Check the internal consistency of a property declaration with +/// an explicit ownership qualifier. +static void checkPropertyDeclWithOwnership(Sema &S, + ObjCPropertyDecl *property) { if (property->isInvalidDecl()) return; ObjCPropertyDecl::PropertyAttributeKind propertyKind @@ -70,8 +72,7 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { Qualifiers::ObjCLifetime propertyLifetime = property->getType().getObjCLifetime(); - // Nothing to do if we don't have a lifetime. - if (propertyLifetime == Qualifiers::OCL_None) return; + assert(propertyLifetime != Qualifiers::OCL_None); Qualifiers::ObjCLifetime expectedLifetime = getImpliedARCOwnership(propertyKind, property->getType()); @@ -127,6 +128,40 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop, CheckPropertyAgainstProtocol(S, Prop, P, Known); } +static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) { + // In GC mode, just look for the __weak qualifier. + if (S.getLangOpts().getGC() != LangOptions::NonGC) { + if (T.isObjCGCWeak()) return ObjCDeclSpec::DQ_PR_weak; + + // In ARC/MRC, look for an explicit ownership qualifier. + // For some reason, this only applies to __weak. + } else if (auto ownership = T.getObjCLifetime()) { + switch (ownership) { + case Qualifiers::OCL_Weak: + return ObjCDeclSpec::DQ_PR_weak; + case Qualifiers::OCL_Strong: + return ObjCDeclSpec::DQ_PR_strong; + case Qualifiers::OCL_ExplicitNone: + return ObjCDeclSpec::DQ_PR_unsafe_unretained; + case Qualifiers::OCL_Autoreleasing: + case Qualifiers::OCL_None: + return 0; + } + llvm_unreachable("bad qualifier"); + } + + return 0; +} + +static unsigned getOwnershipRule(unsigned attr) { + return attr & (ObjCPropertyDecl::OBJC_PR_assign | + ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_weak | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_unsafe_unretained); +} + Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, @@ -140,19 +175,25 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, FD.D.setObjCWeakProperty((Attributes & ObjCDeclSpec::DQ_PR_weak) != 0); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); QualType T = TSI->getType(); - Attributes |= deduceWeakPropertyFromType(T); + if (!getOwnershipRule(Attributes)) { + Attributes |= deducePropertyOwnershipFromType(*this, T); + } bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || // default is readwrite! !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); - // property is defaulted to 'assign' if it is readwrite and is - // not retain or copy - bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || - (isReadWrite && - !(Attributes & ObjCDeclSpec::DQ_PR_retain) && - !(Attributes & ObjCDeclSpec::DQ_PR_strong) && - !(Attributes & ObjCDeclSpec::DQ_PR_copy) && - !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) && - !(Attributes & ObjCDeclSpec::DQ_PR_weak))); + + // Property defaults to 'assign' if it is readwrite, unless this is ARC + // and the type is retainable. + bool isAssign; + if (Attributes & (ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_unsafe_unretained)) { + isAssign = true; + } else if (getOwnershipRule(Attributes) || !isReadWrite) { + isAssign = false; + } else { + isAssign = (!getLangOpts().ObjCAutoRefCount || + !T->isObjCRetainableType()); + } // Proceed with constructing the ObjCPropertyDecls. ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext); @@ -185,8 +226,9 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, (isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCProtocolDecl>(ClassDecl))); - if (getLangOpts().ObjCAutoRefCount) - checkARCPropertyDecl(*this, Res); + // Check consistency if the type has explicit ownership qualification. + if (Res->getType().getObjCLifetime()) + checkPropertyDeclWithOwnership(*this, Res); llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos; if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { @@ -293,15 +335,6 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName, } -static unsigned getOwnershipRule(unsigned attr) { - return attr & (ObjCPropertyDecl::OBJC_PR_assign | - ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_weak | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_unsafe_unretained); -} - ObjCPropertyDecl * Sema::HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, @@ -425,7 +458,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly; PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite; - PIkind |= deduceWeakPropertyFromType(PIDecl->getType()); + PIkind |= deducePropertyOwnershipFromType(*this, PIDecl->getType()); unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes); unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind); if (PrimaryClassMemoryModel && ClassExtensionMemoryModel && @@ -972,12 +1005,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // the property type. } else { if (!getLangOpts().ObjCWeak) { - if (getLangOpts().ObjCWeakRuntime) { - Diag(PropertyDiagLoc, diag::err_arc_weak_disabled); - } else { - Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime); + // Only complain here when synthesizing an ivar. + if (!Ivar) { + Diag(PropertyDiagLoc, + getLangOpts().ObjCWeakRuntime + ? diag::err_synthesizing_arc_weak_property_disabled + : diag::err_synthesizing_arc_weak_property_no_runtime); + Diag(property->getLocation(), diag::note_property_declare); } - Diag(property->getLocation(), diag::note_property_declare); + CompleteTypeErr = true; // suppress later diagnostics about the ivar } else { isARCWeak = true; if (const ObjCObjectPointerType *ObjT = @@ -2201,15 +2237,6 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl); QualType PropertyTy = PropertyDecl->getType(); - unsigned PropertyOwnership = getOwnershipRule(Attributes); - - // 'readonly' property with no obvious lifetime. - // its life time will be determined by its backing ivar. - if (getLangOpts().ObjCAutoRefCount && - Attributes & ObjCDeclSpec::DQ_PR_readonly && - PropertyTy->isObjCRetainableType() && - !PropertyOwnership) - return; // Check for copy or retain on non-object types. if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy | @@ -2319,16 +2346,14 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, // Warn if user supplied no assignment attribute, property is // readwrite, and this is an object type. - if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_unsafe_unretained | - ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong | - ObjCDeclSpec::DQ_PR_weak)) && - PropertyTy->isObjCObjectPointerType()) { - if (getLangOpts().ObjCAutoRefCount) - // With arc, @property definitions should default to (strong) when - // not specified; including when property is 'readonly'. - PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); - else if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly)) { + if (!getOwnershipRule(Attributes) && PropertyTy->isObjCRetainableType()) { + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) { + // do nothing + } else if (getLangOpts().ObjCAutoRefCount) { + // With arc, @property definitions should default to strong when + // not specified. + PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + } else if (PropertyTy->isObjCObjectPointerType()) { bool isAnyClassTy = (PropertyTy->isObjCClassType() || PropertyTy->isObjCQualifiedClassType()); @@ -2347,7 +2372,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, if (getLangOpts().getGC() == LangOptions::NonGC) Diag(Loc, diag::warn_objc_property_default_assign_on_object); } - } + } // FIXME: Implement warning dependent on NSCopying being // implemented. See also: |

