summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2015-10-27 04:54:50 +0000
committerJohn McCall <rjmccall@apple.com>2015-10-27 04:54:50 +0000
commitb61e14e5962a2b881db3b7515e8c4f6f762fa0f2 (patch)
tree535f9505a6499d7a3da0a52f714fb3699730f527 /clang/lib/Sema
parentc692688cbd6e1f73426ebf3d660d05677603427d (diff)
downloadbcm5719-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.cpp53
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp18
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp127
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:
OpenPOWER on IntegriCloud