summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaDeclObjC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclObjC.cpp')
-rw-r--r--lib/Sema/SemaDeclObjC.cpp540
1 files changed, 447 insertions, 93 deletions
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index de9097e..aa8152b 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -16,14 +16,96 @@
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Sema/DeclSpec.h"
#include "llvm/ADT/DenseSet.h"
using namespace clang;
+/// Check whether the given method, which must be in the 'init'
+/// family, is a valid member of that family.
+///
+/// \param receiverTypeIfCall - if null, check this as if declaring it;
+/// if non-null, check this as if making a call to it with the given
+/// receiver type
+///
+/// \return true to indicate that there was an error and appropriate
+/// actions were taken
+bool Sema::checkInitMethod(ObjCMethodDecl *method,
+ QualType receiverTypeIfCall) {
+ if (method->isInvalidDecl()) return true;
+
+ // This castAs is safe: methods that don't return an object
+ // pointer won't be inferred as inits and will reject an explicit
+ // objc_method_family(init).
+
+ // We ignore protocols here. Should we? What about Class?
+
+ const ObjCObjectType *result = method->getResultType()
+ ->castAs<ObjCObjectPointerType>()->getObjectType();
+
+ if (result->isObjCId()) {
+ return false;
+ } else if (result->isObjCClass()) {
+ // fall through: always an error
+ } else {
+ ObjCInterfaceDecl *resultClass = result->getInterface();
+ assert(resultClass && "unexpected object type!");
+
+ // It's okay for the result type to still be a forward declaration
+ // if we're checking an interface declaration.
+ if (resultClass->isForwardDecl()) {
+ if (receiverTypeIfCall.isNull() &&
+ !isa<ObjCImplementationDecl>(method->getDeclContext()))
+ return false;
+
+ // Otherwise, we try to compare class types.
+ } else {
+ // If this method was declared in a protocol, we can't check
+ // anything unless we have a receiver type that's an interface.
+ const ObjCInterfaceDecl *receiverClass = 0;
+ if (isa<ObjCProtocolDecl>(method->getDeclContext())) {
+ if (receiverTypeIfCall.isNull())
+ return false;
+
+ receiverClass = receiverTypeIfCall->castAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+
+ // This can be null for calls to e.g. id<Foo>.
+ if (!receiverClass) return false;
+ } else {
+ receiverClass = method->getClassInterface();
+ assert(receiverClass && "method not associated with a class!");
+ }
+
+ // If either class is a subclass of the other, it's fine.
+ if (receiverClass->isSuperClassOf(resultClass) ||
+ resultClass->isSuperClassOf(receiverClass))
+ return false;
+ }
+ }
+
+ SourceLocation loc = method->getLocation();
+
+ // If we're in a system header, and this is not a call, just make
+ // the method unusable.
+ if (receiverTypeIfCall.isNull() && getSourceManager().isInSystemHeader(loc)) {
+ method->addAttr(new (Context) UnavailableAttr(loc, Context,
+ "init method returns a type unrelated to its receiver type"));
+ return true;
+ }
+
+ // Otherwise, it's an error.
+ Diag(loc, diag::err_arc_init_method_unrelated_result_type);
+ method->setInvalidDecl();
+ return true;
+}
+
bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
const ObjCMethodDecl *Overridden,
bool IsImplementation) {
@@ -36,7 +118,7 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
QualType ResultType = NewMethod->getResultType();
SourceRange ResultTypeRange;
if (const TypeSourceInfo *ResultTypeInfo
- = NewMethod->getResultTypeSourceInfo())
+ = NewMethod->getResultTypeSourceInfo())
ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
// Figure out which class this method is part of, if any.
@@ -73,7 +155,15 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
return false;
}
-
+/// \brief Check for consistency between a given method declaration and the
+/// methods it overrides within the class hierarchy.
+///
+/// This method walks the inheritance hierarchy starting at the given
+/// declaration context (\p DC), invoking Sema::CheckObjCMethodOverride() with
+/// the given new method (\p NewMethod) and any method it directly overrides
+/// in the hierarchy. Sema::CheckObjCMethodOverride() is responsible for
+/// checking consistency, e.g., among return types for methods that return a
+/// related result type.
static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
DeclContext *DC,
bool SkipCurrent = true) {
@@ -99,10 +189,10 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
return true;
}
-
+
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
- IEnd = Class->protocol_end();
+ IEnd = Class->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -115,7 +205,7 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
- IEnd = Category->protocol_end();
+ IEnd = Category->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -126,7 +216,7 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
// Look through protocols.
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
- IEnd = Protocol->protocol_end();
+ IEnd = Protocol->protocol_end();
I != IEnd; ++I)
if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
return true;
@@ -141,13 +231,13 @@ bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
DeclContext *DC) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
-
+
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
-
+
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
-
+
if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
return ::CheckObjCMethodOverrides(*this, NewMethod,
Impl->getClassInterface());
@@ -159,6 +249,55 @@ bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
}
+/// \brief Check a method declaration for compatibility with the Objective-C
+/// ARC conventions.
+static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
+ ObjCMethodFamily family = method->getMethodFamily();
+ switch (family) {
+ case OMF_None:
+ case OMF_dealloc:
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ case OMF_self:
+ return false;
+
+ case OMF_init:
+ // If the method doesn't obey the init rules, don't bother annotating it.
+ if (S.checkInitMethod(method, QualType()))
+ return true;
+
+ method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(),
+ S.Context));
+
+ // Don't add a second copy of this attribute, but otherwise don't
+ // let it be suppressed.
+ if (method->hasAttr<NSReturnsRetainedAttr>())
+ return false;
+ break;
+
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ if (method->hasAttr<NSReturnsRetainedAttr>() ||
+ method->hasAttr<NSReturnsNotRetainedAttr>() ||
+ method->hasAttr<NSReturnsAutoreleasedAttr>())
+ return false;
+ break;
+
+ case OMF_performSelector:
+ // we don't annotate performSelector's
+ return true;
+
+ }
+
+ method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
+ S.Context));
+ return false;
+}
+
static void DiagnoseObjCImplementedDeprecations(Sema &S,
NamedDecl *ND,
SourceLocation ImplLoc,
@@ -212,6 +351,31 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
if ((*PI)->getIdentifier())
PushOnScopeChains(*PI, FnBodyScope);
}
+
+ // In ARC, disallow definition of retain/release/autorelease/retainCount
+ if (getLangOptions().ObjCAutoRefCount) {
+ switch (MDecl->getMethodFamily()) {
+ case OMF_retain:
+ case OMF_retainCount:
+ case OMF_release:
+ case OMF_autorelease:
+ Diag(MDecl->getLocation(), diag::err_arc_illegal_method_def)
+ << MDecl->getSelector();
+ break;
+
+ case OMF_None:
+ case OMF_dealloc:
+ case OMF_alloc:
+ case OMF_init:
+ case OMF_mutableCopy:
+ case OMF_copy:
+ case OMF_new:
+ case OMF_self:
+ case OMF_performSelector:
+ break;
+ }
+ }
+
// Warn on implementating deprecated methods under
// -Wdeprecated-implementations flag.
if (ObjCInterfaceDecl *IC = MDecl->getClassInterface())
@@ -284,9 +448,10 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!PrevDecl) {
// Try to correct for a typo in the superclass name.
- LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
+ NULL, NULL, false, CTC_NoKeywords);
+ if ((PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
Diag(SuperLoc, diag::err_undef_superclass_suggest)
<< SuperName << ClassName << PrevDecl->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_previous_decl)
@@ -333,10 +498,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!SuperClassDecl)
Diag(SuperLoc, diag::err_undef_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
- else if (SuperClassDecl->isForwardDecl())
- Diag(SuperLoc, diag::err_undef_superclass)
+ else if (SuperClassDecl->isForwardDecl()) {
+ Diag(SuperLoc, diag::err_forward_superclass)
<< SuperClassDecl->getDeclName() << ClassName
<< SourceRange(AtInterfaceLoc, ClassLoc);
+ Diag(SuperClassDecl->getLocation(), diag::note_forward_class);
+ SuperClassDecl = 0;
+ }
}
IDecl->setSuperClass(SuperClassDecl);
IDecl->setSuperClassLoc(SuperLoc);
@@ -494,12 +662,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second);
if (!PDecl) {
- LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second,
- LookupObjCProtocolName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (PDecl = R.getAsSingle<ObjCProtocolDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
+ LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords);
+ if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
- << ProtocolId[i].first << R.getLookupName();
+ << ProtocolId[i].first << Corrected.getCorrection();
Diag(PDecl->getLocation(), diag::note_previous_decl)
<< PDecl->getDeclName();
}
@@ -736,20 +904,20 @@ Decl *Sema::ActOnStartClassImplementation(
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
- LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
- (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
+ NULL, NULL, false, CTC_NoKeywords);
+ if ((IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
// Suggest the (potentially) correct interface name. However, put the
// fix-it hint itself in a separate note, since changing the name in
// the warning would make the fix-it change semantics.However, don't
// provide a code-modification hint or use the typo name for recovery,
// because this is just a warning. The program may actually be correct.
+ DeclarationName CorrectedName = Corrected.getCorrection();
Diag(ClassLoc, diag::warn_undef_interface_suggest)
- << ClassName << R.getLookupName();
- Diag(IDecl->getLocation(), diag::note_previous_decl)
- << R.getLookupName()
- << FixItHint::CreateReplacement(ClassLoc,
- R.getLookupName().getAsString());
+ << ClassName << CorrectedName;
+ Diag(IDecl->getLocation(), diag::note_previous_decl) << CorrectedName
+ << FixItHint::CreateReplacement(ClassLoc, CorrectedName.getAsString());
IDecl = 0;
} else {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
@@ -915,6 +1083,9 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
bool &IncompleteImpl, unsigned DiagID) {
+ // No point warning no definition of method which is 'unavailable'.
+ if (method->hasAttr<UnavailableAttr>())
+ return;
if (!IncompleteImpl) {
Diag(ImpLoc, diag::warn_incomplete_impl);
IncompleteImpl = true;
@@ -1091,11 +1262,84 @@ static void CheckMethodOverrideParam(Sema &S,
S.Diag(IfaceVar->getLocation(), diag::note_previous_definition)
<< getTypeRange(IfaceVar->getTypeSourceInfo());
}
-
+
+/// In ARC, check whether the conventional meanings of the two methods
+/// match. If they don't, it's a hard error.
+static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
+ ObjCMethodDecl *decl) {
+ ObjCMethodFamily implFamily = impl->getMethodFamily();
+ ObjCMethodFamily declFamily = decl->getMethodFamily();
+ if (implFamily == declFamily) return false;
+
+ // Since conventions are sorted by selector, the only possibility is
+ // that the types differ enough to cause one selector or the other
+ // to fall out of the family.
+ assert(implFamily == OMF_None || declFamily == OMF_None);
+
+ // No further diagnostics required on invalid declarations.
+ if (impl->isInvalidDecl() || decl->isInvalidDecl()) return true;
+
+ const ObjCMethodDecl *unmatched = impl;
+ ObjCMethodFamily family = declFamily;
+ unsigned errorID = diag::err_arc_lost_method_convention;
+ unsigned noteID = diag::note_arc_lost_method_convention;
+ if (declFamily == OMF_None) {
+ unmatched = decl;
+ family = implFamily;
+ errorID = diag::err_arc_gained_method_convention;
+ noteID = diag::note_arc_gained_method_convention;
+ }
+
+ // Indexes into a %select clause in the diagnostic.
+ enum FamilySelector {
+ F_alloc, F_copy, F_mutableCopy = F_copy, F_init, F_new
+ };
+ FamilySelector familySelector = FamilySelector();
+
+ switch (family) {
+ case OMF_None: llvm_unreachable("logic error, no method convention");
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_dealloc:
+ case OMF_retainCount:
+ case OMF_self:
+ case OMF_performSelector:
+ // Mismatches for these methods don't change ownership
+ // conventions, so we don't care.
+ return false;
+
+ case OMF_init: familySelector = F_init; break;
+ case OMF_alloc: familySelector = F_alloc; break;
+ case OMF_copy: familySelector = F_copy; break;
+ case OMF_mutableCopy: familySelector = F_mutableCopy; break;
+ case OMF_new: familySelector = F_new; break;
+ }
+
+ enum ReasonSelector { R_NonObjectReturn, R_UnrelatedReturn };
+ ReasonSelector reasonSelector;
+
+ // The only reason these methods don't fall within their families is
+ // due to unusual result types.
+ if (unmatched->getResultType()->isObjCObjectPointerType()) {
+ reasonSelector = R_UnrelatedReturn;
+ } else {
+ reasonSelector = R_NonObjectReturn;
+ }
+
+ S.Diag(impl->getLocation(), errorID) << familySelector << reasonSelector;
+ S.Diag(decl->getLocation(), noteID) << familySelector << reasonSelector;
+
+ return true;
+}
void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
ObjCMethodDecl *MethodDecl,
bool IsProtocolMethodDecl) {
+ if (getLangOptions().ObjCAutoRefCount &&
+ checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl))
+ return;
+
CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl,
IsProtocolMethodDecl);
@@ -1204,7 +1448,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl);
}
-/// MatchAllMethodDeclarations - Check methods declaraed in interface or
+/// MatchAllMethodDeclarations - Check methods declared in interface
/// or protocol against those declared in their implementations.
///
void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
@@ -1422,48 +1666,117 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
return CDecl;
}
+static bool tryMatchRecordTypes(ASTContext &Context,
+ Sema::MethodMatchStrategy strategy,
+ const Type *left, const Type *right);
+
+static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy,
+ QualType leftQT, QualType rightQT) {
+ const Type *left =
+ Context.getCanonicalType(leftQT).getUnqualifiedType().getTypePtr();
+ const Type *right =
+ Context.getCanonicalType(rightQT).getUnqualifiedType().getTypePtr();
+
+ if (left == right) return true;
+
+ // If we're doing a strict match, the types have to match exactly.
+ if (strategy == Sema::MMS_strict) return false;
+
+ if (left->isIncompleteType() || right->isIncompleteType()) return false;
+
+ // Otherwise, use this absurdly complicated algorithm to try to
+ // validate the basic, low-level compatibility of the two types.
+
+ // As a minimum, require the sizes and alignments to match.
+ if (Context.getTypeInfo(left) != Context.getTypeInfo(right))
+ return false;
+
+ // Consider all the kinds of non-dependent canonical types:
+ // - functions and arrays aren't possible as return and parameter types
+
+ // - vector types of equal size can be arbitrarily mixed
+ if (isa<VectorType>(left)) return isa<VectorType>(right);
+ if (isa<VectorType>(right)) return false;
+
+ // - references should only match references of identical type
+ // - structs, unions, and Objective-C objects must match more-or-less
+ // exactly
+ // - everything else should be a scalar
+ if (!left->isScalarType() || !right->isScalarType())
+ return tryMatchRecordTypes(Context, strategy, left, right);
+
+ // Make scalars agree in kind, except count bools as chars.
+ Type::ScalarTypeKind leftSK = left->getScalarTypeKind();
+ Type::ScalarTypeKind rightSK = right->getScalarTypeKind();
+ if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral;
+ if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral;
+
+ // Note that data member pointers and function member pointers don't
+ // intermix because of the size differences.
+
+ return (leftSK == rightSK);
+}
+
+static bool tryMatchRecordTypes(ASTContext &Context,
+ Sema::MethodMatchStrategy strategy,
+ const Type *lt, const Type *rt) {
+ assert(lt && rt && lt != rt);
+
+ if (!isa<RecordType>(lt) || !isa<RecordType>(rt)) return false;
+ RecordDecl *left = cast<RecordType>(lt)->getDecl();
+ RecordDecl *right = cast<RecordType>(rt)->getDecl();
+
+ // Require union-hood to match.
+ if (left->isUnion() != right->isUnion()) return false;
+
+ // Require an exact match if either is non-POD.
+ if ((isa<CXXRecordDecl>(left) && !cast<CXXRecordDecl>(left)->isPOD()) ||
+ (isa<CXXRecordDecl>(right) && !cast<CXXRecordDecl>(right)->isPOD()))
+ return false;
+
+ // Require size and alignment to match.
+ if (Context.getTypeInfo(lt) != Context.getTypeInfo(rt)) return false;
+
+ // Require fields to match.
+ RecordDecl::field_iterator li = left->field_begin(), le = left->field_end();
+ RecordDecl::field_iterator ri = right->field_begin(), re = right->field_end();
+ for (; li != le && ri != re; ++li, ++ri) {
+ if (!matchTypes(Context, strategy, li->getType(), ri->getType()))
+ return false;
+ }
+ return (li == le && ri == re);
+}
/// MatchTwoMethodDeclarations - Checks that two methods have matching type and
/// returns true, or false, accordingly.
/// TODO: Handle protocol list; such as id<p1,p2> in type comparisons
-bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
- const ObjCMethodDecl *PrevMethod,
- bool matchBasedOnSizeAndAlignment,
- bool matchBasedOnStrictEqulity) {
- QualType T1 = Context.getCanonicalType(Method->getResultType());
- QualType T2 = Context.getCanonicalType(PrevMethod->getResultType());
-
- if (T1 != T2) {
- // The result types are different.
- if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
- return false;
- // Incomplete types don't have a size and alignment.
- if (T1->isIncompleteType() || T2->isIncompleteType())
- return false;
- // Check is based on size and alignment.
- if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
- return false;
- }
+bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
+ const ObjCMethodDecl *right,
+ MethodMatchStrategy strategy) {
+ if (!matchTypes(Context, strategy,
+ left->getResultType(), right->getResultType()))
+ return false;
- ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
- E = Method->param_end();
- ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin();
+ if (getLangOptions().ObjCAutoRefCount &&
+ (left->hasAttr<NSReturnsRetainedAttr>()
+ != right->hasAttr<NSReturnsRetainedAttr>() ||
+ left->hasAttr<NSConsumesSelfAttr>()
+ != right->hasAttr<NSConsumesSelfAttr>()))
+ return false;
- for (; ParamI != E; ++ParamI, ++PrevI) {
- assert(PrevI != PrevMethod->param_end() && "Param mismatch");
- T1 = Context.getCanonicalType((*ParamI)->getType());
- T2 = Context.getCanonicalType((*PrevI)->getType());
- if (T1 != T2) {
- // The result types are different.
- if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
- return false;
- // Incomplete types don't have a size and alignment.
- if (T1->isIncompleteType() || T2->isIncompleteType())
- return false;
- // Check is based on size and alignment.
- if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
- return false;
- }
+ ObjCMethodDecl::param_iterator
+ li = left->param_begin(), le = left->param_end(), ri = right->param_begin();
+
+ for (; li != le; ++li, ++ri) {
+ assert(ri != right->param_end() && "Param mismatch");
+ ParmVarDecl *lparm = *li, *rparm = *ri;
+
+ if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType()))
+ return false;
+
+ if (getLangOptions().ObjCAutoRefCount &&
+ lparm->hasAttr<NSConsumedAttr>() != rparm->hasAttr<NSConsumedAttr>())
+ return false;
}
return true;
}
@@ -1505,8 +1818,10 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
// We've seen a method with this name, see if we have already seen this type
// signature.
- for (ObjCMethodList *List = &Entry; List; List = List->Next)
- if (MatchTwoMethodDeclarations(Method, List->Method)) {
+ for (ObjCMethodList *List = &Entry; List; List = List->Next) {
+ bool match = MatchTwoMethodDeclarations(Method, List->Method);
+
+ if (match) {
ObjCMethodDecl *PrevObjCMethod = List->Method;
PrevObjCMethod->setDefined(impl);
// If a method is deprecated, push it in the global pool.
@@ -1523,6 +1838,7 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
}
return;
}
+ }
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
@@ -1530,6 +1846,25 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
}
+/// Determines if this is an "acceptable" loose mismatch in the global
+/// method pool. This exists mostly as a hack to get around certain
+/// global mismatches which we can't afford to make warnings / errors.
+/// Really, what we want is a way to take a method out of the global
+/// method pool.
+static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
+ ObjCMethodDecl *other) {
+ if (!chosen->isInstanceMethod())
+ return false;
+
+ Selector sel = chosen->getSelector();
+ if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")
+ return false;
+
+ // Don't complain about mismatches for -length if the method we
+ // chose has an integral result type.
+ return (chosen->getResultType()->isIntegerType());
+}
+
ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
bool warn, bool instance) {
@@ -1543,32 +1878,52 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
- bool strictSelectorMatch = receiverIdOrClass && warn &&
- (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
- R.getBegin()) !=
- Diagnostic::Ignored);
if (warn && MethList.Method && MethList.Next) {
- bool issueWarning = false;
+ bool issueDiagnostic = false, issueError = false;
+
+ // We support a warning which complains about *any* difference in
+ // method signature.
+ bool strictSelectorMatch =
+ (receiverIdOrClass && warn &&
+ (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+ R.getBegin()) !=
+ Diagnostic::Ignored));
if (strictSelectorMatch)
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- // This checks if the methods differ in type mismatch.
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, false, true))
- issueWarning = true;
+ if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+ MMS_strict)) {
+ issueDiagnostic = true;
+ break;
+ }
}
- if (!issueWarning)
+ // If we didn't see any strict differences, we won't see any loose
+ // differences. In ARC, however, we also need to check for loose
+ // mismatches, because most of them are errors.
+ if (!strictSelectorMatch ||
+ (issueDiagnostic && getLangOptions().ObjCAutoRefCount))
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- // This checks if the methods differ by size & alignment.
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
- issueWarning = true;
+ // This checks if the methods differ in type mismatch.
+ if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+ MMS_loose) &&
+ !isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
+ issueDiagnostic = true;
+ if (getLangOptions().ObjCAutoRefCount)
+ issueError = true;
+ break;
+ }
}
- if (issueWarning) {
- if (strictSelectorMatch)
+ if (issueDiagnostic) {
+ if (issueError)
+ Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
+ else if (strictSelectorMatch)
Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
else
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
- Diag(MethList.Method->getLocStart(), diag::note_using)
+
+ Diag(MethList.Method->getLocStart(),
+ issueError ? diag::note_possibility : diag::note_using)
<< MethList.Method->getSourceRange();
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
Diag(Next->Method->getLocStart(), diag::note_also_found)
@@ -1796,6 +2151,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
DefaultSynthesizeProperties(S, IC, IDecl);
ImplMethodsVsClassMethods(S, IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
+ DiagnoseOwningPropertyGetterSynthesis(IC);
if (LangOpts.ObjCNonFragileABI2)
while (IDecl->getSuperClass()) {
@@ -1968,7 +2324,7 @@ Decl *Sema::ActOnMethodDeclaration(
} else {
ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI);
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
- ArgType = adjustParameterType(ArgType);
+ ArgType = Context.getAdjustedParameterType(ArgType);
}
LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc,
@@ -2015,7 +2371,7 @@ Decl *Sema::ActOnMethodDeclaration(
ArgType = Context.getObjCIdType();
else
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
- ArgType = adjustParameterType(ArgType);
+ ArgType = Context.getAdjustedParameterType(ArgType);
if (ArgType->isObjCObjectType()) {
Diag(Param->getLocation(),
diag::err_object_cannot_be_passed_returned_by_value)
@@ -2104,7 +2460,11 @@ Decl *Sema::ActOnMethodDeclaration(
mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
}
- if (!ObjCMethod->hasRelatedResultType() &&
+ bool ARCError = false;
+ if (getLangOptions().ObjCAutoRefCount)
+ ARCError = CheckARCMethodDecl(*this, ObjCMethod);
+
+ if (!ObjCMethod->hasRelatedResultType() && !ARCError &&
getLangOptions().ObjCInferRelatedResultType) {
bool InferRelatedResultType = false;
switch (ObjCMethod->getMethodFamily()) {
@@ -2114,6 +2474,7 @@ Decl *Sema::ActOnMethodDeclaration(
case OMF_mutableCopy:
case OMF_release:
case OMF_retainCount:
+ case OMF_performSelector:
break;
case OMF_alloc:
@@ -2255,15 +2616,8 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
- TagDecl *OwnedDecl = 0;
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType ExceptionType = TInfo->getType();
-
- if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
- // Objective-C++: Types shall not be defined in exception types.
- Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
- << Context.getTypeDeclType(OwnedDecl);
- }
VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType,
D.getSourceRange().getBegin(),
OpenPOWER on IntegriCloud