diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index a4ea1c5ff03170473f1c4b66e4c6fa641ebdfe28..cdfa11203eea653e95ba433f24e440a6de145562 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -384,26 +384,31 @@ def note_required_for_protocol_at :
   Note<"required for direct or indirect protocol %0">;
 
 def warn_conflicting_ret_types : Warning<
-  "conflicting return type in implementation of %0: %1 vs %2">;
+  "conflicting return type in "
+  "%select{implementation|declaration}3 of %0: %1 vs %2">;
 def warn_conflicting_ret_type_modifiers : Warning<
   "conflicting distributed object modifiers on return type "
-  "in implementation of %0">,
+  "in %select{implementation|declaration}1 of %0">,
   InGroup<DiagGroup<"distributed-object-modifiers">>;
 def warn_non_covariant_ret_types : Warning<
-  "conflicting return type in implementation of %0: %1 vs %2">,
+  "conflicting return type in "
+  "%select{implementation|declaration}3 of %0: %1 vs %2">,
   InGroup<DiagGroup<"method-signatures">>, DefaultIgnore;
 
 def warn_conflicting_param_types : Warning<
-  "conflicting parameter types in implementation of %0: %1 vs %2">;
+  "conflicting parameter types in "
+  "%select{implementation|declaration}3 of %0: %1 vs %2">;
 def warn_conflicting_param_modifiers : Warning<
   "conflicting distributed object modifiers on parameter type "
-  "in implementation of %0">,
+  "in %select{implementation|declaration}1 of %0">,
   InGroup<DiagGroup<"distributed-object-modifiers">>;
 def warn_non_contravariant_param_types : Warning<
-  "conflicting parameter types in implementation of %0: %1 vs %2">,
+  "conflicting parameter types in "
+  "%select{implementation|declaration}3 of %0: %1 vs %2">,
   InGroup<DiagGroup<"method-signatures">>, DefaultIgnore;
 def warn_conflicting_variadic :Warning<
-  "conflicting variadic declaration of method and its implementation">;
+  "conflicting variadic declaration of method and its "
+  "%select{implementation|declaration}0">;
 
 def warn_implements_nscopying : Warning<
 "default assign attribute on property %0 which implements "
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 35bcf074ff9261ad8fece3f9d9c4c9eeea371588..41d0e8a17673e19c6f7476f8e0205ff6e101cb37 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1762,9 +1762,10 @@ public:
 
   void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
                            bool &IncompleteImpl, unsigned DiagID);
-  void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
+  void WarnConflictingTypedMethods(ObjCMethodDecl *Method,
                                    ObjCMethodDecl *MethodDecl,
-                                   bool IsProtocolMethodDecl);
+                                   bool IsProtocolMethodDecl,
+                                   bool IsDeclaration = false);
 
   bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl,
                           ObjCInterfaceDecl *IDecl);
@@ -1887,6 +1888,11 @@ public:
                                   bool &IncompleteImpl,
                                   bool ImmediateClass);
 
+  /// MatchMethodsInClassAndItsProtocol - Check that any redeclaration of
+  /// method in protocol in its qualified class match in their type and
+  /// issue warnings otherwise.
+  void MatchMethodsInClassAndItsProtocol(const ObjCInterfaceDecl *CDecl);
+
 private:
   /// AddMethodToGlobalPool - Add an instance or factory method to the global
   /// pool. See descriptoin of AddInstanceMethodToGlobalPool.
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index da3bedd12a350760749dffe8df49276e93dce930..e9a39b614e85014f2b1f5bfc091fda90089ae449 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1074,13 +1074,14 @@ static SourceRange getTypeRange(TypeSourceInfo *TSI) {
 static void CheckMethodOverrideReturn(Sema &S,
                                       ObjCMethodDecl *MethodImpl,
                                       ObjCMethodDecl *MethodDecl,
-                                      bool IsProtocolMethodDecl) {
+                                      bool IsProtocolMethodDecl,
+                                      bool IsDeclaration) {
   if (IsProtocolMethodDecl &&
       (MethodDecl->getObjCDeclQualifier() !=
        MethodImpl->getObjCDeclQualifier())) {
     S.Diag(MethodImpl->getLocation(), 
            diag::warn_conflicting_ret_type_modifiers)
-        << MethodImpl->getDeclName()
+        << MethodImpl->getDeclName() << IsDeclaration
         << getTypeRange(MethodImpl->getResultTypeSourceInfo());
     S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
         << getTypeRange(MethodDecl->getResultTypeSourceInfo());
@@ -1113,6 +1114,7 @@ static void CheckMethodOverrideReturn(Sema &S,
     << MethodImpl->getDeclName()
     << MethodDecl->getResultType()
     << MethodImpl->getResultType()
+    << IsDeclaration
     << getTypeRange(MethodImpl->getResultTypeSourceInfo());
   S.Diag(MethodDecl->getLocation(), diag::note_previous_definition)
     << getTypeRange(MethodDecl->getResultTypeSourceInfo());
@@ -1123,14 +1125,15 @@ static void CheckMethodOverrideParam(Sema &S,
                                      ObjCMethodDecl *MethodDecl,
                                      ParmVarDecl *ImplVar,
                                      ParmVarDecl *IfaceVar,
-                                     bool IsProtocolMethodDecl) {
+                                     bool IsProtocolMethodDecl,
+                                     bool IsDeclaration) {
   if (IsProtocolMethodDecl &&
       (ImplVar->getObjCDeclQualifier() !=
        IfaceVar->getObjCDeclQualifier())) {
     S.Diag(ImplVar->getLocation(), 
            diag::warn_conflicting_param_modifiers)
         << getTypeRange(ImplVar->getTypeSourceInfo())
-        << MethodImpl->getDeclName();
+        << MethodImpl->getDeclName() << IsDeclaration;
     S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration)
         << getTypeRange(IfaceVar->getTypeSourceInfo());   
   }
@@ -1162,7 +1165,8 @@ static void CheckMethodOverrideParam(Sema &S,
 
   S.Diag(ImplVar->getLocation(), DiagID)
     << getTypeRange(ImplVar->getTypeSourceInfo())
-    << MethodImpl->getDeclName() << IfaceTy << ImplTy;
+    << MethodImpl->getDeclName() << IfaceTy << ImplTy 
+    << IsDeclaration;
   S.Diag(IfaceVar->getLocation(), diag::note_previous_definition)
     << getTypeRange(IfaceVar->getTypeSourceInfo());
 }
@@ -1239,22 +1243,24 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
 
 void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
                                        ObjCMethodDecl *MethodDecl,
-                                       bool IsProtocolMethodDecl) {
+                                       bool IsProtocolMethodDecl,
+                                       bool IsDeclaration) {
   if (getLangOptions().ObjCAutoRefCount &&
       checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl))
     return;
 
   CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, 
-                            IsProtocolMethodDecl);
+                            IsProtocolMethodDecl, IsDeclaration);
 
   for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(),
        IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
        IM != EM; ++IM, ++IF)
     CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF,
-                             IsProtocolMethodDecl);
+                             IsProtocolMethodDecl, IsDeclaration);
 
   if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) {
-    Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic);
+    Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic)
+      << IsDeclaration;
     Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
   }
 }
@@ -1427,6 +1433,11 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
       MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
                                  IMPDecl,
                                  (*PI), IncompleteImpl, false);
+    
+    // Check for any type mismtch of methods declared in class 
+    // and methods declared in protocol.
+    MatchMethodsInClassAndItsProtocol(I);
+    
     if (I->getSuperClass())
       MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
                                  IMPDecl,
@@ -1434,6 +1445,99 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
   }
 }
 
+static void MatchMethodsInClassAndOneProtocol(Sema &S, 
+                                              Sema::SelectorSet &InsMap,
+                                              Sema::SelectorSet &ClsMap,
+                                              const ObjCContainerDecl *IDecl,
+                                              const ObjCProtocolDecl *PDecl) {
+  if (!InsMap.empty())
+    for (ObjCInterfaceDecl::instmeth_iterator IM = PDecl->instmeth_begin(),
+         E = PDecl->instmeth_end(); IM != E; ++IM) {
+      Selector Sel = (*IM)->getSelector();
+      if (InsMap.count(Sel)) {
+        ObjCMethodDecl *ProtoMethodDecl = PDecl->getInstanceMethod(Sel);
+        ObjCMethodDecl *ClsMethodDecl = IDecl->getInstanceMethod(Sel);
+        if (ProtoMethodDecl && ClsMethodDecl)
+          S.WarnConflictingTypedMethods(
+                                      ClsMethodDecl, 
+                                      ProtoMethodDecl, true, true);
+        InsMap.erase(Sel);
+      }
+      if (InsMap.empty())
+        break;
+    }
+  if (!ClsMap.empty())
+    for (ObjCInterfaceDecl::classmeth_iterator IM = PDecl->classmeth_begin(),
+         E = PDecl->classmeth_end(); IM != E; ++IM) {
+      Selector Sel = (*IM)->getSelector();
+      if (ClsMap.count(Sel)) {
+        ObjCMethodDecl *ProtoMethodDecl = PDecl->getClassMethod(Sel);
+        ObjCMethodDecl *ClsMethodDecl = IDecl->getClassMethod(Sel);
+        if (ProtoMethodDecl && ClsMethodDecl)
+          S.WarnConflictingTypedMethods(
+                                        ClsMethodDecl, 
+                                        ProtoMethodDecl, true, true);
+        ClsMap.erase(Sel);
+      }
+      if (ClsMap.empty())
+        break;
+    }
+  if (InsMap.empty() && ClsMap.empty())
+    return;
+  
+  for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+       PE = PDecl->protocol_end(); PI != PE; ++PI)
+    MatchMethodsInClassAndOneProtocol(S, InsMap, ClsMap, IDecl, (*PI));
+}
+
+void Sema::MatchMethodsInClassAndItsProtocol(const ObjCInterfaceDecl *CDecl) {
+  if (CDecl->all_referenced_protocol_begin() ==
+      CDecl->all_referenced_protocol_end())
+    return;
+  
+  SelectorSet InsMap, ClsMap;
+  for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
+       E = CDecl->instmeth_end(); I != E; ++I)
+    if (!InsMap.count((*I)->getSelector()))
+      InsMap.insert((*I)->getSelector());
+  
+  for (ObjCInterfaceDecl::classmeth_iterator
+       I = CDecl->classmeth_begin(), E = CDecl->classmeth_end(); I != E; ++I)
+    if (!ClsMap.count((*I)->getSelector()))
+      ClsMap.insert((*I)->getSelector());
+  
+  if (!InsMap.empty() || !ClsMap.empty())
+    for (ObjCInterfaceDecl::all_protocol_iterator
+         PI = CDecl->all_referenced_protocol_begin(),
+         E = CDecl->all_referenced_protocol_end(); PI != E; ++PI)
+      MatchMethodsInClassAndOneProtocol(*this, InsMap, ClsMap, CDecl, (*PI));
+  
+  // Also for class extensions
+  if (!CDecl->getFirstClassExtension())
+    return;
+  
+  for (const ObjCCategoryDecl *ClsExtDecl = CDecl->getFirstClassExtension();
+       ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
+    InsMap.clear();
+    ClsMap.clear();
+    for (ObjCCategoryDecl::instmeth_iterator I = ClsExtDecl->instmeth_begin(),
+         E = ClsExtDecl->instmeth_end(); I != E; ++I)
+      if (!InsMap.count((*I)->getSelector()))
+        InsMap.insert((*I)->getSelector());
+    for (ObjCCategoryDecl::classmeth_iterator I = ClsExtDecl->classmeth_begin(),
+         E = ClsExtDecl->classmeth_end(); I != E; ++I)
+      if (!ClsMap.count((*I)->getSelector()))
+        ClsMap.insert((*I)->getSelector());
+    if (InsMap.empty() && ClsMap.empty())
+      continue;
+    for (ObjCInterfaceDecl::all_protocol_iterator
+         PI = CDecl->all_referenced_protocol_begin(),
+         E = CDecl->all_referenced_protocol_end(); PI != E; ++PI)
+      MatchMethodsInClassAndOneProtocol(*this, InsMap, ClsMap, ClsExtDecl, (*PI));
+  }
+}
+
+
 void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
                                      ObjCContainerDecl* CDecl,
                                      bool IncompleteImpl) {
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index ee1a6b4b782e0149c12cafdc3e15f93ce72241dd..e835bebfbf4407eaf39c9d262a31756c239e31e7 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -92,7 +92,7 @@ typedef struct _NSZone NSZone;
 + (id)allocWithZone:(NSZone *)zone;
 + (id)alloc;
 - (void)dealloc;
-- (void)release;
+- (oneway void)release;
 - (id)copy;
 @end
 @interface NSObject (NSCoderMethods)
diff --git a/test/SemaObjC/class-protocol-method-match.m b/test/SemaObjC/class-protocol-method-match.m
new file mode 100644
index 0000000000000000000000000000000000000000..be1c1e03f376d4b2d08955e0b62e9587f2633a67
--- /dev/null
+++ b/test/SemaObjC/class-protocol-method-match.m
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1  -fsyntax-only -verify %s
+// rdar://9352731
+
+@protocol Bar 
+@required
+- (unsigned char) baz; // expected-note {{previous definition is here}}
+- (char) ok;
+- (void) also_ok;
+@end
+
+@protocol Bar1 
+@required
+- (unsigned char) baz;
+- (unsigned char) also_ok;
+- (void) ban : (int) arg, ...; // expected-note {{previous declaration is here}}
+@end
+
+@protocol Baz <Bar, Bar1>
+- (void) bar : (unsigned char)arg; // expected-note {{previous definition is here}}
+- (void) ok;
+- (char) bak; // expected-note {{previous definition is here}}
+@end
+
+@interface Foo <Baz>
+- (void) baz;  // expected-warning {{conflicting return type in declaration of 'baz': 'unsigned char' vs 'void'}}
+- (void) bar : (unsigned char*)arg; // expected-warning {{conflicting parameter types in declaration of 'bar:': 'unsigned char' vs 'unsigned char *'}}
+- (void) ok;
+- (void) also_ok;
+- (void) still_ok;
+- (void) ban : (int) arg; // expected-warning {{conflicting variadic declaration of method and its declaration}}
+@end
+
+@interface Foo()
+- (void) bak; // expected-warning {{conflicting return type in declaration of 'bak': 'char' vs 'void'}}
+@end
+
+@implementation Foo
+- (void) baz {}
+- (void) bar : (unsigned char*)arg {}
+- (void) ok {}
+- (void) also_ok {}
+- (void) still_ok {}
+- (void) ban : (int) arg {}
+- (void) bak {}
+@end
+
diff --git a/test/SemaObjC/dist-object-modifiers.m b/test/SemaObjC/dist-object-modifiers.m
index 98a9ce6cdc52742b6a620f8e2c5b0157aed0f034..77e9938177a1a9d398fca63bd3139610e6f76165 100644
--- a/test/SemaObjC/dist-object-modifiers.m
+++ b/test/SemaObjC/dist-object-modifiers.m
@@ -4,12 +4,12 @@
 @protocol P
 - (bycopy id)serverPID; // expected-note {{previous declaration is here}}
 - (void)doStuff:(bycopy id)clientId; // expected-note {{previous declaration is here}}
-- (bycopy id)Ok;
+- (bycopy id)Ok; // expected-note {{previous declaration is here}}
 + (oneway id) stillMore : (byref id)Arg : (bycopy oneway id)Arg1;  // expected-note 3 {{previous declaration is here}}
 @end
 
 @interface I <P>
-- (id)Ok;
+- (id)Ok; // expected-warning {{conflicting distributed object modifiers on return type in declaration of 'Ok'}}
 @end
 
 @implementation I