diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -225,43 +225,56 @@ if (Res->getType().getObjCLifetime()) checkPropertyDeclWithOwnership(*this, Res); - llvm::SmallPtrSet KnownProtos; - if (ObjCInterfaceDecl *IFace = dyn_cast(ClassDecl)) { - // For a class, compare the property against a property in our superclass. - bool FoundInSuper = false; - ObjCInterfaceDecl *CurrentInterfaceDecl = IFace; - while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) { - if (ObjCPropertyDecl *SuperProp = - Super->lookup(Res->getDeclName()).find_first()) { - DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false); - FoundInSuper = true; - break; + // For an instance property, check consistency with the properties of + // superclasses. + if (Res->isInstanceProperty()) { + llvm::SmallPtrSet KnownProtos; + if (ObjCInterfaceDecl *IFace = dyn_cast(ClassDecl)) { + // For a class, compare the property against a property in our superclass. + bool FoundInSuper = false; + ObjCInterfaceDecl *CurrentInterfaceDecl = IFace; + while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) { + ObjCPropertyDecl *SuperProp = nullptr; + for (auto *LookupResult : Super->lookup(Res->getDeclName())) { + if (auto *Prop = dyn_cast(LookupResult)) { + if (Prop->isInstanceProperty()) { + SuperProp = Prop; + break; + } + } + } + if (SuperProp) { + DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), + false); + FoundInSuper = true; + break; + } + CurrentInterfaceDecl = Super; } - CurrentInterfaceDecl = Super; - } - if (FoundInSuper) { - // Also compare the property against a property in our protocols. - for (auto *P : CurrentInterfaceDecl->protocols()) { - CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos); + if (FoundInSuper) { + // Also compare the property against a property in our protocols. + for (auto *P : CurrentInterfaceDecl->protocols()) { + CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos); + } + } else { + // Slower path: look in all protocols we referenced. + for (auto *P : IFace->all_referenced_protocols()) { + CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos); + } } + } else if (ObjCCategoryDecl *Cat = dyn_cast(ClassDecl)) { + // We don't check if class extension. Because properties in class + // extension are meant to override some of the attributes and checking has + // already done when property in class extension is constructed. + if (!Cat->IsClassExtension()) + for (auto *P : Cat->protocols()) + CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos); } else { - // Slower path: look in all protocols we referenced. - for (auto *P : IFace->all_referenced_protocols()) { + ObjCProtocolDecl *Proto = cast(ClassDecl); + for (auto *P : Proto->protocols()) CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos); - } } - } else if (ObjCCategoryDecl *Cat = dyn_cast(ClassDecl)) { - // We don't check if class extension. Because properties in class extension - // are meant to override some of the attributes and checking has already done - // when property in class extension is constructed. - if (!Cat->IsClassExtension()) - for (auto *P : Cat->protocols()) - CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos); - } else { - ObjCProtocolDecl *Proto = cast(ClassDecl); - for (auto *P : Proto->protocols()) - CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos); } ActOnDocumentableDecl(Res); diff --git a/clang/test/SemaObjC/class-property-inheritance.m b/clang/test/SemaObjC/class-property-inheritance.m new file mode 100644 --- /dev/null +++ b/clang/test/SemaObjC/class-property-inheritance.m @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +@class MyObject; + +@interface TopClassWithInstanceProperty +@property(nullable, readonly, strong) MyObject *foo; +@end + +@interface SubClassWithClassProperty : TopClassWithInstanceProperty +@property(nonnull, readonly, copy, class) MyObject *foo; +@end + +@interface TopClassWithClassProperty +@property(nullable, readonly, class) MyObject *foo; +@end + +@interface SubClassWithInstanceProperty : TopClassWithClassProperty +@property(nonnull, readonly, copy) MyObject *foo; +@end