r251874 - Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.

Nico Weber via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 3 11:03:22 PST 2015


r254622, thanks! The attached patch does the same for debug info. It
doesn't completely restore the behavior before your change though:
The DIObjCProperty now always goes with the redeclared line, while it
didn't always do this before (see test). This seems like a progression
though.

On Thu, Dec 3, 2015 at 9:25 AM, Douglas Gregor <dgregor at apple.com> wrote:

> This looks great, please commit. Thanks Nico!
>
> - Doug
>
> On Dec 3, 2015, at 8:58 AM, Nico Weber <thakis at chromium.org> wrote:
>
> Here's a version that gets that right.
>
> On Wed, Dec 2, 2015 at 8:16 PM, Douglas Gregor <dgregor at apple.com> wrote:
>
>>
>> On Dec 2, 2015, at 7:22 PM, Nico Weber <thakis at chromium.org> wrote:
>>
>> It looks like one place in CGObjCMac.cpp still walks
>> ObjCContainerDecl::properties(), while it probably should
>> use collectPropertiesToImplement() which you extended to also find
>> properites from known_extensions(). The attached patch has a fix that
>> restores the observed prior behavior and a reduced lit test that makes sure
>> this doesn't regress. Does this look right?
>>
>>
>> Thank you for working on this!
>>
>> It’s close; I suggest testing the case where you have a readonly property
>> in the class definition and a readwrite property with the same name in an
>> extension, to make sure we get the correct metadata (readwrite, without
>> duplicates).
>>
>>
>> If so, something like this would probably be needed
>> in CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty) in
>> CGDebugInfo.cpp too.
>>
>>
>> Yep, there too.
>>
>> - Doug
>>
>>
>> On Tue, Dec 1, 2015 at 2:44 PM, Nico Weber <thakis at chromium.org> wrote:
>>
>>> Actually, looking at it again Foo derives from NSObject and shouldn't
>>> shadow anything. So maybe this isn't an intentional behavior change even?
>>>
>>> On Tue, Dec 1, 2015 at 2:39 PM, Nico Weber <thakis at chromium.org> wrote:
>>>
>>>> Hi Doug and Argyrios,
>>>>
>>>> this is breaking things for us. We have a class ObjCPropertyReleaser
>>>> that automatically releases synthesized Objective-C properties marked
>>>> retain or copy [1]. It does this by looking at the result
>>>> of property_getAttributes() and looking for 'C' or '&' (copy or retain).
>>>>
>>>> After this change, this longer works. Here's a reduced example:
>>>>
>>>> $ cat main.mm
>>>> #import <Foundation/Foundation.h>
>>>> #import <UIKit/UIKit.h>
>>>>
>>>> @interface Foo : NSObject
>>>> @end
>>>>
>>>> @interface Foo ()
>>>>
>>>> @property(nonatomic, retain) UIView* contentView;
>>>> @end
>>>>
>>>> @implementation Foo
>>>> @synthesize contentView = _contentView;
>>>> @end
>>>>
>>>> $ newclang++ -isysroot
>>>> /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator9.1.sdk
>>>> -c main.mm -o main.o && strings main.o | grep "&,N,V_contentView"
>>>> # Nothing found.
>>>>
>>>> $ oldclang++ -isysroot
>>>> /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator9.1.sdk
>>>> -c main.mm -o main.o && strings main.o | grep "&,N,V_contentView"
>>>> T@"UIView",&,N,V_contentView
>>>> # ^ Found as expected
>>>>
>>>>
>>>> I suppose this is intentional and the fix is to not shadow readonly
>>>> superclass properties? Finding these is a bit difficult though as clang
>>>> doesn't warn about this as far as I can tell.
>>>>
>>>> Thanks,
>>>> Nico
>>>>
>>>> 1:
>>>> https://code.google.com/p/chromium/codesearch#chromium/src/base/mac/objc_property_releaser.h
>>>>
>>>> On Mon, Nov 2, 2015 at 8:22 PM, Douglas Gregor via cfe-commits <
>>>> cfe-commits at lists.llvm.org> wrote:
>>>>
>>>>> … and I forgot the most important part, which is that this is based on
>>>>> the good work of Mr. Kyrtzidis that I failed to acknowledge in the commit
>>>>> message.
>>>>>
>>>>>         - Doug
>>>>>
>>>>>
>>>>> > On Nov 2, 2015, at 5:15 PM, Douglas Gregor via cfe-commits <
>>>>> cfe-commits at lists.llvm.org> wrote:
>>>>> >
>>>>> > Author: dgregor
>>>>> > Date: Mon Nov  2 19:15:46 2015
>>>>> > New Revision: 251874
>>>>> >
>>>>> > URL: http://llvm.org/viewvc/llvm-project?rev=251874&view=rev
>>>>> > Log:
>>>>> > Stop back-patching 'readonly' Objective-C properties with
>>>>> 'readwrite' ones.
>>>>> >
>>>>> > A 'readonly' Objective-C property declared in the primary class can
>>>>> > effectively be shadowed by a 'readwrite' property declared within an
>>>>> > extension of that class, so long as the types and attributes of the
>>>>> > two property declarations are compatible.
>>>>> >
>>>>> > Previously, this functionality was implemented by back-patching the
>>>>> > original 'readonly' property to make it 'readwrite', destroying
>>>>> source
>>>>> > information and causing some hideously redundant, incorrect
>>>>> > code. Simplify the implementation to express how this should actually
>>>>> > be modeled: as a separate property declaration in the extension that
>>>>> > shadows (via the name lookup rules) the declaration in the primary
>>>>> > class. While here, correct some broken Fix-Its, eliminate a pile of
>>>>> > redundant code, clean up the ARC migrator's handling of properties
>>>>> > declared in extensions, and fix debug info's naming of methods that
>>>>> > come from categories.
>>>>> >
>>>>> > A wonderous side effect of doing this write is that it eliminates the
>>>>> > "AddedObjCPropertyInClassExtension" method from the AST mutation
>>>>> > listener, which in turn eliminates the last place where we rewrite
>>>>> > entire declarations in a chained PCH file or a module file. This
>>>>> > change (which fixes rdar://problem/18475765) will allow us to
>>>>> > eliminate the rewritten-decls logic from the serialization library,
>>>>> > and fixes a crash (rdar://problem/23247794) illustrated by the
>>>>> > test/PCH/chain-categories.m example.
>>>>> >
>>>>> >
>>>>> > Modified:
>>>>> >    cfe/trunk/include/clang/AST/ASTMutationListener.h
>>>>> >    cfe/trunk/include/clang/AST/DeclObjC.h
>>>>> >    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>>>> >    cfe/trunk/include/clang/Sema/Sema.h
>>>>> >    cfe/trunk/include/clang/Serialization/ASTWriter.h
>>>>> >    cfe/trunk/lib/ARCMigrate/TransProperties.cpp
>>>>> >    cfe/trunk/lib/AST/DeclObjC.cpp
>>>>> >    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
>>>>> >    cfe/trunk/lib/Frontend/MultiplexConsumer.cpp
>>>>> >    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
>>>>> >    cfe/trunk/lib/Sema/SemaExprObjC.cpp
>>>>> >    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
>>>>> >    cfe/trunk/lib/Serialization/ASTWriter.cpp
>>>>> >    cfe/trunk/test/FixIt/atomic-property.m
>>>>> >    cfe/trunk/test/Index/complete-kvc.m
>>>>> >    cfe/trunk/test/Modules/ModuleDebugInfo.m
>>>>> >    cfe/trunk/test/PCH/chain-categories.m
>>>>> >    cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m
>>>>> >    cfe/trunk/test/SemaObjC/property-3.m
>>>>> >    cfe/trunk/test/SemaObjC/property-in-class-extension-1.m
>>>>> >    cfe/trunk/test/SemaObjCXX/property-invalid-type.mm
>>>>> >
>>>>> > Modified: cfe/trunk/include/clang/AST/ASTMutationListener.h
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTMutationListener.h?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/include/clang/AST/ASTMutationListener.h (original)
>>>>> > +++ cfe/trunk/include/clang/AST/ASTMutationListener.h Mon Nov  2
>>>>> 19:15:46 2015
>>>>> > @@ -92,18 +92,6 @@ public:
>>>>> >   virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl
>>>>> *CatD,
>>>>> >                                             const ObjCInterfaceDecl
>>>>> *IFD) {}
>>>>> >
>>>>> > -  /// \brief A objc class extension redeclared or introduced a
>>>>> property.
>>>>> > -  ///
>>>>> > -  /// \param Prop the property in the class extension
>>>>> > -  ///
>>>>> > -  /// \param OrigProp the property from the original interface that
>>>>> was declared
>>>>> > -  /// or null if the property was introduced.
>>>>> > -  ///
>>>>> > -  /// \param ClassExt the class extension.
>>>>> > -  virtual void AddedObjCPropertyInClassExtension(const
>>>>> ObjCPropertyDecl *Prop,
>>>>> > -                                            const ObjCPropertyDecl
>>>>> *OrigProp,
>>>>> > -                                            const ObjCCategoryDecl
>>>>> *ClassExt) {}
>>>>> > -
>>>>> >   /// \brief A declaration is marked used which was not previously
>>>>> marked used.
>>>>> >   ///
>>>>> >   /// \param D the declaration marked used
>>>>> >
>>>>> > Modified: cfe/trunk/include/clang/AST/DeclObjC.h
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/include/clang/AST/DeclObjC.h (original)
>>>>> > +++ cfe/trunk/include/clang/AST/DeclObjC.h Mon Nov  2 19:15:46 2015
>>>>> > @@ -2524,11 +2524,6 @@ public:
>>>>> >     PropertyAttributesAsWritten = PRVal;
>>>>> >   }
>>>>> >
>>>>> > - void makeitReadWriteAttribute() {
>>>>> > -    PropertyAttributes &= ~OBJC_PR_readonly;
>>>>> > -    PropertyAttributes |= OBJC_PR_readwrite;
>>>>> > - }
>>>>> > -
>>>>> >   // Helper methods for accessing attributes.
>>>>> >
>>>>> >   /// isReadOnly - Return true iff the property has a setter.
>>>>> >
>>>>> > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>>>>> > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Nov  2
>>>>> 19:15:46 2015
>>>>> > @@ -884,7 +884,8 @@ def err_property_type : Error<"property
>>>>> > def error_missing_property_context : Error<
>>>>> >   "missing context for property implementation declaration">;
>>>>> > def error_bad_property_decl : Error<
>>>>> > -  "property implementation must have its declaration in interface
>>>>> %0">;
>>>>> > +  "property implementation must have its declaration in interface
>>>>> %0 or one of "
>>>>> > +  "its extensions">;
>>>>> > def error_category_property : Error<
>>>>> >   "property declared in category %0 cannot be implemented in "
>>>>> >   "class implementation">;
>>>>> >
>>>>> > Modified: cfe/trunk/include/clang/Sema/Sema.h
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/include/clang/Sema/Sema.h (original)
>>>>> > +++ cfe/trunk/include/clang/Sema/Sema.h Mon Nov  2 19:15:46 2015
>>>>> > @@ -3047,7 +3047,7 @@ public:
>>>>> >   /// warning) when atomic property has one but not the other
>>>>> user-declared
>>>>> >   /// setter or getter.
>>>>> >   void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl,
>>>>> > -                                       ObjCContainerDecl* IDecl);
>>>>> > +                                       ObjCInterfaceDecl* IDecl);
>>>>> >
>>>>> >   void DiagnoseOwningPropertyGetterSynthesis(const
>>>>> ObjCImplementationDecl *D);
>>>>> >
>>>>> >
>>>>> > Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
>>>>> > +++ cfe/trunk/include/clang/Serialization/ASTWriter.h Mon Nov  2
>>>>> 19:15:46 2015
>>>>> > @@ -876,9 +876,6 @@ public:
>>>>> >   void FunctionDefinitionInstantiated(const FunctionDecl *D)
>>>>> override;
>>>>> >   void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
>>>>> >                                     const ObjCInterfaceDecl *IFD)
>>>>> override;
>>>>> > -  void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl
>>>>> *Prop,
>>>>> > -                                    const ObjCPropertyDecl
>>>>> *OrigProp,
>>>>> > -                                    const ObjCCategoryDecl
>>>>> *ClassExt) override;
>>>>> >   void DeclarationMarkedUsed(const Decl *D) override;
>>>>> >   void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
>>>>> >   void RedefinedHiddenDefinition(const NamedDecl *D, Module *M)
>>>>> override;
>>>>> >
>>>>> > Modified: cfe/trunk/lib/ARCMigrate/TransProperties.cpp
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransProperties.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/lib/ARCMigrate/TransProperties.cpp (original)
>>>>> > +++ cfe/trunk/lib/ARCMigrate/TransProperties.cpp Mon Nov  2 19:15:46
>>>>> 2015
>>>>> > @@ -96,6 +96,10 @@ public:
>>>>> >
>>>>> >     collectProperties(iface, AtProps);
>>>>> >
>>>>> > +    // Look through extensions.
>>>>> > +    for (auto *Ext : iface->visible_extensions())
>>>>> > +      collectProperties(Ext, AtProps);
>>>>> > +
>>>>> >     typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
>>>>> >         prop_impl_iterator;
>>>>> >     for (prop_impl_iterator
>>>>> > @@ -137,19 +141,6 @@ public:
>>>>> >       Transaction Trans(Pass.TA);
>>>>> >       rewriteProperty(props, atLoc);
>>>>> >     }
>>>>> > -
>>>>> > -    AtPropDeclsTy AtExtProps;
>>>>> > -    // Look through extensions.
>>>>> > -    for (auto *Ext : iface->visible_extensions())
>>>>> > -      collectProperties(Ext, AtExtProps, &AtProps);
>>>>> > -
>>>>> > -    for (AtPropDeclsTy::iterator
>>>>> > -           I = AtExtProps.begin(), E = AtExtProps.end(); I != E;
>>>>> ++I) {
>>>>> > -      SourceLocation atLoc =
>>>>> SourceLocation::getFromRawEncoding(I->first);
>>>>> > -      PropsTy &props = I->second;
>>>>> > -      Transaction Trans(Pass.TA);
>>>>> > -      doActionForExtensionProp(props, atLoc);
>>>>> > -    }
>>>>> >   }
>>>>> >
>>>>> > private:
>>>>> > @@ -177,15 +168,6 @@ private:
>>>>> >     }
>>>>> >   }
>>>>> >
>>>>> > -  void doActionForExtensionProp(PropsTy &props, SourceLocation
>>>>> atLoc) {
>>>>> > -    llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I;
>>>>> > -    I = ActionOnProp.find(props[0].PropD->getIdentifier());
>>>>> > -    if (I == ActionOnProp.end())
>>>>> > -      return;
>>>>> > -
>>>>> > -    doPropAction(I->second, props, atLoc, false);
>>>>> > -  }
>>>>> > -
>>>>> >   void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
>>>>> >     ObjCPropertyDecl::PropertyAttributeKind propAttrs =
>>>>> getPropertyAttrs(props);
>>>>> >
>>>>> >
>>>>> > Modified: cfe/trunk/lib/AST/DeclObjC.cpp
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/lib/AST/DeclObjC.cpp (original)
>>>>> > +++ cfe/trunk/lib/AST/DeclObjC.cpp Mon Nov  2 19:15:46 2015
>>>>> > @@ -161,6 +161,15 @@ ObjCPropertyDecl::findPropertyDecl(const
>>>>> >         return nullptr;
>>>>> >   }
>>>>> >
>>>>> > +  // If context is class, then lookup property in its extensions.
>>>>> > +  // This comes before property is looked up in primary class.
>>>>> > +  if (auto *IDecl = dyn_cast<ObjCInterfaceDecl>(DC)) {
>>>>> > +    for (const auto *Ext : IDecl->known_extensions())
>>>>> > +      if (ObjCPropertyDecl *PD =
>>>>> ObjCPropertyDecl::findPropertyDecl(Ext,
>>>>> > +
>>>>> propertyID))
>>>>> > +        return PD;
>>>>> > +  }
>>>>> > +
>>>>> >   DeclContext::lookup_result R = DC->lookup(propertyID);
>>>>> >   for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I !=
>>>>> E;
>>>>> >        ++I)
>>>>> > @@ -190,6 +199,15 @@ ObjCPropertyDecl *ObjCContainerDecl::Fin
>>>>> >       if (Def->isHidden())
>>>>> >         return nullptr;
>>>>> >   }
>>>>> > +
>>>>> > +  // Search the extensions of a class first; they override what's in
>>>>> > +  // the class itself.
>>>>> > +  if (const auto *ClassDecl = dyn_cast<ObjCInterfaceDecl>(this)) {
>>>>> > +    for (const auto *Ext : ClassDecl->visible_extensions()) {
>>>>> > +      if (auto *P = Ext->FindPropertyDeclaration(PropertyId))
>>>>> > +        return P;
>>>>> > +    }
>>>>> > +  }
>>>>> >
>>>>> >   if (ObjCPropertyDecl *PD =
>>>>> >         ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this),
>>>>> PropertyId))
>>>>> > @@ -207,7 +225,7 @@ ObjCPropertyDecl *ObjCContainerDecl::Fin
>>>>> >     }
>>>>> >     case Decl::ObjCInterface: {
>>>>> >       const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this);
>>>>> > -      // Look through categories (but not extensions).
>>>>> > +      // Look through categories (but not extensions; they were
>>>>> handled above).
>>>>> >       for (const auto *Cat : OID->visible_categories()) {
>>>>> >         if (!Cat->IsClassExtension())
>>>>> >           if (ObjCPropertyDecl *P =
>>>>> Cat->FindPropertyDeclaration(PropertyId))
>>>>> > @@ -327,6 +345,13 @@ void ObjCInterfaceDecl::collectPropertie
>>>>> >     PM[Prop->getIdentifier()] = Prop;
>>>>> >     PO.push_back(Prop);
>>>>> >   }
>>>>> > +  for (const auto *Ext : known_extensions()) {
>>>>> > +    const ObjCCategoryDecl *ClassExt = Ext;
>>>>> > +    for (auto *Prop : ClassExt->properties()) {
>>>>> > +      PM[Prop->getIdentifier()] = Prop;
>>>>> > +      PO.push_back(Prop);
>>>>> > +    }
>>>>> > +  }
>>>>> >   for (const auto *PI : all_referenced_protocols())
>>>>> >     PI->collectPropertiesToImplement(PM, PO);
>>>>> >   // Note, the properties declared only in class extensions are
>>>>> still copied
>>>>> > @@ -1182,18 +1207,47 @@ ObjCMethodDecl::findPropertyDecl(bool Ch
>>>>> >
>>>>> >   if (isPropertyAccessor()) {
>>>>> >     const ObjCContainerDecl *Container =
>>>>> cast<ObjCContainerDecl>(getParent());
>>>>> > -    // If container is class extension, find its primary class.
>>>>> > -    if (const ObjCCategoryDecl *CatDecl =
>>>>> dyn_cast<ObjCCategoryDecl>(Container))
>>>>> > -      if (CatDecl->IsClassExtension())
>>>>> > -        Container = CatDecl->getClassInterface();
>>>>> > -
>>>>> >     bool IsGetter = (NumArgs == 0);
>>>>> >
>>>>> > -    for (const auto *I : Container->properties()) {
>>>>> > -      Selector NextSel = IsGetter ? I->getGetterName()
>>>>> > -                                  : I->getSetterName();
>>>>> > -      if (NextSel == Sel)
>>>>> > -        return I;
>>>>> > +    /// Local function that attempts to find a matching property
>>>>> within the
>>>>> > +    /// given Objective-C container.
>>>>> > +    auto findMatchingProperty =
>>>>> > +      [&](const ObjCContainerDecl *Container) -> const
>>>>> ObjCPropertyDecl * {
>>>>> > +
>>>>> > +      for (const auto *I : Container->properties()) {
>>>>> > +        Selector NextSel = IsGetter ? I->getGetterName()
>>>>> > +                                    : I->getSetterName();
>>>>> > +        if (NextSel == Sel)
>>>>> > +          return I;
>>>>> > +      }
>>>>> > +
>>>>> > +      return nullptr;
>>>>> > +    };
>>>>> > +
>>>>> > +    // Look in the container we were given.
>>>>> > +    if (const auto *Found = findMatchingProperty(Container))
>>>>> > +      return Found;
>>>>> > +
>>>>> > +    // If we're in a category or extension, look in the main class.
>>>>> > +    const ObjCInterfaceDecl *ClassDecl = nullptr;
>>>>> > +    if (const auto *Category =
>>>>> dyn_cast<ObjCCategoryDecl>(Container)) {
>>>>> > +      ClassDecl = Category->getClassInterface();
>>>>> > +      if (const auto *Found = findMatchingProperty(ClassDecl))
>>>>> > +        return Found;
>>>>> > +    } else {
>>>>> > +      // Determine whether the container is a class.
>>>>> > +      ClassDecl = dyn_cast<ObjCInterfaceDecl>(Container);
>>>>> > +    }
>>>>> > +
>>>>> > +    // If we have a class, check its visible extensions.
>>>>> > +    if (ClassDecl) {
>>>>> > +      for (const auto *Ext : ClassDecl->visible_extensions()) {
>>>>> > +        if (Ext == Container)
>>>>> > +          continue;
>>>>> > +
>>>>> > +        if (const auto *Found = findMatchingProperty(Ext))
>>>>> > +          return Found;
>>>>> > +      }
>>>>> >     }
>>>>> >
>>>>> >     llvm_unreachable("Marked as a property accessor but no property
>>>>> found!");
>>>>> >
>>>>> > Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
>>>>> > +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Mon Nov  2 19:15:46 2015
>>>>> > @@ -216,6 +216,13 @@ StringRef CGDebugInfo::getObjCMethodName
>>>>> >   } else if (const ObjCInterfaceDecl *OID =
>>>>> >                  dyn_cast<const ObjCInterfaceDecl>(DC)) {
>>>>> >     OS << OID->getName();
>>>>> > +  } else if (const ObjCCategoryDecl *OC =
>>>>> dyn_cast<ObjCCategoryDecl>(DC)) {
>>>>> > +    if (OC->IsClassExtension()) {
>>>>> > +      OS << OC->getClassInterface()->getName();
>>>>> > +    } else {
>>>>> > +      OS << ((const NamedDecl
>>>>> *)OC)->getIdentifier()->getNameStart() << '('
>>>>> > +         << OC->getIdentifier()->getNameStart() << ')';
>>>>> > +    }
>>>>> >   } else if (const ObjCCategoryImplDecl *OCD =
>>>>> >                  dyn_cast<const ObjCCategoryImplDecl>(DC)) {
>>>>> >     OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart()
>>>>> << '('
>>>>> >
>>>>> > Modified: cfe/trunk/lib/Frontend/MultiplexConsumer.cpp
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/MultiplexConsumer.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/lib/Frontend/MultiplexConsumer.cpp (original)
>>>>> > +++ cfe/trunk/lib/Frontend/MultiplexConsumer.cpp Mon Nov  2 19:15:46
>>>>> 2015
>>>>> > @@ -122,9 +122,6 @@ public:
>>>>> >   void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
>>>>> >                                     const ObjCInterfaceDecl *IFD)
>>>>> override;
>>>>> >   void FunctionDefinitionInstantiated(const FunctionDecl *D)
>>>>> override;
>>>>> > -  void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl
>>>>> *Prop,
>>>>> > -                                    const ObjCPropertyDecl
>>>>> *OrigProp,
>>>>> > -                                    const ObjCCategoryDecl
>>>>> *ClassExt) override;
>>>>> >   void DeclarationMarkedUsed(const Decl *D) override;
>>>>> >   void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
>>>>> >   void RedefinedHiddenDefinition(const NamedDecl *D, Module *M)
>>>>> override;
>>>>> > @@ -207,13 +204,6 @@ void MultiplexASTMutationListener::Funct
>>>>> >   for (auto &Listener : Listeners)
>>>>> >     Listener->FunctionDefinitionInstantiated(D);
>>>>> > }
>>>>> > -void
>>>>> MultiplexASTMutationListener::AddedObjCPropertyInClassExtension(
>>>>> > -                                             const ObjCPropertyDecl
>>>>> *Prop,
>>>>> > -                                             const ObjCPropertyDecl
>>>>> *OrigProp,
>>>>> > -                                             const ObjCCategoryDecl
>>>>> *ClassExt) {
>>>>> > -  for (size_t i = 0, e = Listeners.size(); i != e; ++i)
>>>>> > -    Listeners[i]->AddedObjCPropertyInClassExtension(Prop, OrigProp,
>>>>> ClassExt);
>>>>> > -}
>>>>> > void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl
>>>>> *D) {
>>>>> >   for (size_t i = 0, e = Listeners.size(); i != e; ++i)
>>>>> >     Listeners[i]->DeclarationMarkedUsed(D);
>>>>> >
>>>>> > Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
>>>>> > +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Nov  2 19:15:46 2015
>>>>> > @@ -2844,6 +2844,20 @@ void Sema::ImplMethodsVsClassMethods(Sco
>>>>> >   for (const auto *I : IMPDecl->instance_methods())
>>>>> >     InsMap.insert(I->getSelector());
>>>>> >
>>>>> > +  // Add the selectors for getters/setters of @dynamic properties.
>>>>> > +  for (const auto *PImpl : IMPDecl->property_impls()) {
>>>>> > +    // We only care about @dynamic implementations.
>>>>> > +    if (PImpl->getPropertyImplementation() !=
>>>>> ObjCPropertyImplDecl::Dynamic)
>>>>> > +      continue;
>>>>> > +
>>>>> > +    const auto *P = PImpl->getPropertyDecl();
>>>>> > +    if (!P) continue;
>>>>> > +
>>>>> > +    InsMap.insert(P->getGetterName());
>>>>> > +    if (!P->getSetterName().isNull())
>>>>> > +      InsMap.insert(P->getSetterName());
>>>>> > +  }
>>>>> > +
>>>>> >   // Check and see if properties declared in the interface have
>>>>> either 1)
>>>>> >   // an implementation or 2) there is a @synthesize/@dynamic
>>>>> implementation
>>>>> >   // of the property in the @implementation.
>>>>> >
>>>>> > Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
>>>>> > +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Nov  2 19:15:46 2015
>>>>> > @@ -1779,8 +1779,7 @@ HandleExprPropertyRefExpr(const ObjCObje
>>>>> >                           diag::err_property_not_found_forward_class,
>>>>> >                           MemberName, BaseRange))
>>>>> >     return ExprError();
>>>>> > -
>>>>> > -  // Search for a declared property first.
>>>>> > +
>>>>> >   if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member))
>>>>> {
>>>>> >     // Check whether we can reference this property.
>>>>> >     if (DiagnoseUseOfDecl(PD, MemberLoc))
>>>>> >
>>>>> > Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
>>>>> > +++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Mon Nov  2 19:15:46 2015
>>>>> > @@ -262,8 +262,12 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
>>>>> >       }
>>>>> >     }
>>>>> >   } else if (ObjCCategoryDecl *Cat =
>>>>> dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
>>>>> > -    for (auto *P : Cat->protocols())
>>>>> > -      CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
>>>>> > +    // 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<ObjCProtocolDecl>(ClassDecl);
>>>>> >     for (auto *P : Proto->protocols())
>>>>> > @@ -355,46 +359,6 @@ Sema::HandlePropertyInClassExtension(Sco
>>>>> >   IdentifierInfo *PropertyId = FD.D.getIdentifier();
>>>>> >   ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
>>>>> >
>>>>> > -  if (CCPrimary) {
>>>>> > -    // Check for duplicate declaration of this property in current
>>>>> and
>>>>> > -    // other class extensions.
>>>>> > -    for (const auto *Ext : CCPrimary->known_extensions()) {
>>>>> > -      if (ObjCPropertyDecl *prevDecl
>>>>> > -            = ObjCPropertyDecl::findPropertyDecl(Ext, PropertyId)) {
>>>>> > -        Diag(AtLoc, diag::err_duplicate_property);
>>>>> > -        Diag(prevDecl->getLocation(), diag::note_property_declare);
>>>>> > -        return nullptr;
>>>>> > -      }
>>>>> > -    }
>>>>> > -  }
>>>>> > -
>>>>> > -  // Create a new ObjCPropertyDecl with the DeclContext being
>>>>> > -  // the class extension.
>>>>> > -  // FIXME. We should really be using CreatePropertyDecl for this.
>>>>> > -  ObjCPropertyDecl *PDecl =
>>>>> > -    ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(),
>>>>> > -                             PropertyId, AtLoc, LParenLoc, T, TSI);
>>>>> > -  PDecl->setPropertyAttributesAsWritten(
>>>>> > -
>>>>> makePropertyAttributesAsWritten(AttributesAsWritten));
>>>>> > -  if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
>>>>> > -
>>>>> PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
>>>>> > -  if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
>>>>> > -
>>>>> PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
>>>>> > -  if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
>>>>> > -
>>>>> PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
>>>>> > -  if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
>>>>> > -    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
>>>>> > -  if (Attributes & ObjCDeclSpec::DQ_PR_nullability)
>>>>> > -
>>>>> PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability);
>>>>> > -  if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
>>>>> > -
>>>>> PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
>>>>> > -
>>>>> > -  // Set setter/getter selector name. Needed later.
>>>>> > -  PDecl->setGetterName(GetterSel);
>>>>> > -  PDecl->setSetterName(SetterSel);
>>>>> > -  ProcessDeclAttributes(S, PDecl, FD.D);
>>>>> > -  DC->addDecl(PDecl);
>>>>> > -
>>>>> >   // We need to look in the @interface to see if the @property was
>>>>> >   // already declared.
>>>>> >   if (!CCPrimary) {
>>>>> > @@ -403,32 +367,35 @@ Sema::HandlePropertyInClassExtension(Sco
>>>>> >     return nullptr;
>>>>> >   }
>>>>> >
>>>>> > -  // Find the property in continuation class's primary class only.
>>>>> > +  // Find the property in the extended class's primary class or
>>>>> > +  // extensions.
>>>>> >   ObjCPropertyDecl *PIDecl =
>>>>> >     CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId);
>>>>> >
>>>>> > +  // If we found a property in an extension, complain.
>>>>> > +  if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) {
>>>>> > +    Diag(AtLoc, diag::err_duplicate_property);
>>>>> > +    Diag(PIDecl->getLocation(), diag::note_property_declare);
>>>>> > +    return nullptr;
>>>>> > +  }
>>>>> > +
>>>>> > +  // Create a new ObjCPropertyDecl with the DeclContext being
>>>>> > +  // the class extension.
>>>>> > +  ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc,
>>>>> LParenLoc,
>>>>> > +                                               FD, GetterSel,
>>>>> SetterSel,
>>>>> > +                                               isAssign,
>>>>> isReadWrite,
>>>>> > +                                               Attributes,
>>>>> AttributesAsWritten,
>>>>> > +                                               T, TSI,
>>>>> MethodImplKind, DC);
>>>>> > +
>>>>> > +  // If there was no declaration of a property with the same name in
>>>>> > +  // the primary class, we're done.
>>>>> >   if (!PIDecl) {
>>>>> > -    // No matching property found in the primary class. Just fall
>>>>> thru
>>>>> > -    // and add property to continuation class's primary class.
>>>>> > -    ObjCPropertyDecl *PrimaryPDecl =
>>>>> > -      CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc,
>>>>> > -                         FD, GetterSel, SetterSel, isAssign,
>>>>> isReadWrite,
>>>>> > -                         Attributes,AttributesAsWritten, T, TSI,
>>>>> MethodImplKind,
>>>>> > -                         DC);
>>>>> > -
>>>>> > -    // A case of continuation class adding a new property in the
>>>>> class. This
>>>>> > -    // is not what it was meant for. However, gcc supports it and
>>>>> so should we.
>>>>> > -    // Make sure setter/getters are declared here.
>>>>> > -    ProcessPropertyDecl(PrimaryPDecl, CCPrimary,
>>>>> > +    ProcessPropertyDecl(PDecl, CDecl,
>>>>> >                         /* redeclaredProperty = */ nullptr,
>>>>> >                         /* lexicalDC = */ CDecl);
>>>>> > -    PDecl->setGetterMethodDecl(PrimaryPDecl->getGetterMethodDecl());
>>>>> > -    PDecl->setSetterMethodDecl(PrimaryPDecl->getSetterMethodDecl());
>>>>> > -    if (ASTMutationListener *L = Context.getASTMutationListener())
>>>>> > -      L->AddedObjCPropertyInClassExtension(PrimaryPDecl,
>>>>> /*OrigProp=*/nullptr,
>>>>> > -                                           CDecl);
>>>>> > -    return PrimaryPDecl;
>>>>> > +    return PDecl;
>>>>> >   }
>>>>> > +
>>>>> >   if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {
>>>>> >     bool IncompatibleObjC = false;
>>>>> >     QualType ConvertedType;
>>>>> > @@ -451,82 +418,12 @@ Sema::HandlePropertyInClassExtension(Sco
>>>>> >       return nullptr;
>>>>> >     }
>>>>> >   }
>>>>> > -
>>>>> > -  // The property 'PIDecl's readonly attribute will be over-ridden
>>>>> > -  // with continuation class's readwrite property attribute!
>>>>> > +
>>>>> > +  // A readonly property declared in the primary class can be
>>>>> refined
>>>>> > +  // by adding a rewrite property within an extension.
>>>>> > +  // Anything else is an error.
>>>>> >   unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
>>>>> > -  if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly))
>>>>> {
>>>>> > -    PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
>>>>> > -    PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
>>>>> > -    PIkind |= deducePropertyOwnershipFromType(*this,
>>>>> PIDecl->getType());
>>>>> > -    unsigned ClassExtensionMemoryModel =
>>>>> getOwnershipRule(Attributes);
>>>>> > -    unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
>>>>> > -    if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
>>>>> > -        (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) {
>>>>> > -      Diag(AtLoc, diag::warn_property_attr_mismatch);
>>>>> > -      Diag(PIDecl->getLocation(), diag::note_property_declare);
>>>>> > -    }
>>>>> > -    else if (getLangOpts().ObjCAutoRefCount) {
>>>>> > -      QualType PrimaryPropertyQT =
>>>>> > -
>>>>> Context.getCanonicalType(PIDecl->getType()).getUnqualifiedType();
>>>>> > -      if (isa<ObjCObjectPointerType>(PrimaryPropertyQT)) {
>>>>> > -        bool PropertyIsWeak = ((PIkind &
>>>>> ObjCPropertyDecl::OBJC_PR_weak) != 0);
>>>>> > -        Qualifiers::ObjCLifetime PrimaryPropertyLifeTime =
>>>>> > -          PrimaryPropertyQT.getObjCLifetime();
>>>>> > -        if (PrimaryPropertyLifeTime == Qualifiers::OCL_None &&
>>>>> > -            (Attributes & ObjCDeclSpec::DQ_PR_weak) &&
>>>>> > -            !PropertyIsWeak) {
>>>>> > -              Diag(AtLoc,
>>>>> diag::warn_property_implicitly_mismatched);
>>>>> > -              Diag(PIDecl->getLocation(),
>>>>> diag::note_property_declare);
>>>>> > -            }
>>>>> > -        }
>>>>> > -    }
>>>>> > -
>>>>> > -    DeclContext *DC = cast<DeclContext>(CCPrimary);
>>>>> > -    if (!ObjCPropertyDecl::findPropertyDecl(DC,
>>>>> > -
>>>>>  PIDecl->getDeclName().getAsIdentifierInfo())) {
>>>>> > -      // In mrr mode, 'readwrite' property must have an explicit
>>>>> > -      // memory attribute. If none specified, select the default
>>>>> (assign).
>>>>> > -      if (!getLangOpts().ObjCAutoRefCount) {
>>>>> > -        if (!(PIkind & (ObjCDeclSpec::DQ_PR_assign |
>>>>> > -                        ObjCDeclSpec::DQ_PR_retain |
>>>>> > -                        ObjCDeclSpec::DQ_PR_strong |
>>>>> > -                        ObjCDeclSpec::DQ_PR_copy |
>>>>> > -                        ObjCDeclSpec::DQ_PR_unsafe_unretained |
>>>>> > -                        ObjCDeclSpec::DQ_PR_weak)))
>>>>> > -          PIkind |= ObjCPropertyDecl::OBJC_PR_assign;
>>>>> > -      }
>>>>> > -
>>>>> > -      // Protocol is not in the primary class. Must build one for
>>>>> it.
>>>>> > -      ObjCDeclSpec ProtocolPropertyODS;
>>>>> > -      // FIXME. Assuming that
>>>>> ObjCDeclSpec::ObjCPropertyAttributeKind
>>>>> > -      // and ObjCPropertyDecl::PropertyAttributeKind have identical
>>>>> > -      // values.  Should consolidate both into one enum type.
>>>>> > -      ProtocolPropertyODS.
>>>>> > -
>>>>> setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind)
>>>>> > -                            PIkind);
>>>>> > -      // Must re-establish the context from class extension to
>>>>> primary
>>>>> > -      // class context.
>>>>> > -      ContextRAII SavedContext(*this, CCPrimary);
>>>>> > -
>>>>> > -      Decl *ProtocolPtrTy =
>>>>> > -        ActOnProperty(S, AtLoc, LParenLoc, FD, ProtocolPropertyODS,
>>>>> > -                      PIDecl->getGetterName(),
>>>>> > -                      PIDecl->getSetterName(),
>>>>> > -                      isOverridingProperty,
>>>>> > -                      MethodImplKind,
>>>>> > -                      /* lexicalDC = */ CDecl);
>>>>> > -      PIDecl = cast<ObjCPropertyDecl>(ProtocolPtrTy);
>>>>> > -    }
>>>>> > -    PIDecl->makeitReadWriteAttribute();
>>>>> > -    if (Attributes & ObjCDeclSpec::DQ_PR_retain)
>>>>> > -
>>>>> PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
>>>>> > -    if (Attributes & ObjCDeclSpec::DQ_PR_strong)
>>>>> > -
>>>>> PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
>>>>> > -    if (Attributes & ObjCDeclSpec::DQ_PR_copy)
>>>>> > -      PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
>>>>> > -    PIDecl->setSetterName(SetterSel);
>>>>> > -  } else {
>>>>> > +  if (!(isReadWrite && (PIkind &
>>>>> ObjCPropertyDecl::OBJC_PR_readonly))) {
>>>>> >     // Tailor the diagnostics for the common case where a readwrite
>>>>> >     // property is declared both in the @interface and the
>>>>> continuation.
>>>>> >     // This is a common error where the user often intended the
>>>>> original
>>>>> > @@ -541,13 +438,53 @@ Sema::HandlePropertyInClassExtension(Sco
>>>>> >     Diag(PIDecl->getLocation(), diag::note_property_declare);
>>>>> >     return nullptr;
>>>>> >   }
>>>>> > +
>>>>> > +  PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
>>>>> > +  PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
>>>>> > +  PIkind |= deducePropertyOwnershipFromType(*this,
>>>>> PIDecl->getType());
>>>>> > +  unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
>>>>> > +  unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
>>>>> > +  if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
>>>>> > +      (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) {
>>>>> > +    Diag(AtLoc, diag::warn_property_attr_mismatch);
>>>>> > +    Diag(PIDecl->getLocation(), diag::note_property_declare);
>>>>> > +  } else if (getLangOpts().ObjCAutoRefCount) {
>>>>> > +    QualType PrimaryPropertyQT =
>>>>> > +
>>>>> Context.getCanonicalType(PIDecl->getType()).getUnqualifiedType();
>>>>> > +    if (isa<ObjCObjectPointerType>(PrimaryPropertyQT)) {
>>>>> > +      bool PropertyIsWeak = ((PIkind &
>>>>> ObjCPropertyDecl::OBJC_PR_weak) != 0);
>>>>> > +      Qualifiers::ObjCLifetime PrimaryPropertyLifeTime =
>>>>> > +        PrimaryPropertyQT.getObjCLifetime();
>>>>> > +      if (PrimaryPropertyLifeTime == Qualifiers::OCL_None &&
>>>>> > +          (Attributes & ObjCDeclSpec::DQ_PR_weak) &&
>>>>> > +          !PropertyIsWeak) {
>>>>> > +            Diag(AtLoc, diag::warn_property_implicitly_mismatched);
>>>>> > +            Diag(PIDecl->getLocation(),
>>>>> diag::note_property_declare);
>>>>> > +          }
>>>>> > +      }
>>>>> > +  }
>>>>> > +
>>>>> > +  // Check that atomicity of property in class extension matches
>>>>> the previous
>>>>> > +  // declaration.
>>>>> > +  unsigned PDeclAtomicity =
>>>>> > +    PDecl->getPropertyAttributes() & (ObjCDeclSpec::DQ_PR_atomic |
>>>>> ObjCDeclSpec::DQ_PR_nonatomic);
>>>>> > +  unsigned PIDeclAtomicity =
>>>>> > +    PIDecl->getPropertyAttributes() & (ObjCDeclSpec::DQ_PR_atomic |
>>>>> ObjCDeclSpec::DQ_PR_nonatomic);
>>>>> > +  if (PDeclAtomicity != PIDeclAtomicity) {
>>>>> > +    bool PDeclAtomic = (!PDeclAtomicity || PDeclAtomicity &
>>>>> ObjCDeclSpec::DQ_PR_atomic);
>>>>> > +    bool PIDeclAtomic = (!PIDeclAtomicity || PIDeclAtomicity &
>>>>> ObjCDeclSpec::DQ_PR_atomic);
>>>>> > +    if (PDeclAtomic != PIDeclAtomic) {
>>>>> > +      Diag(PDecl->getLocation(), diag::warn_property_attribute)
>>>>> > +        << PDecl->getDeclName() << "atomic"
>>>>> > +        <<
>>>>> cast<ObjCContainerDecl>(PIDecl->getDeclContext())->getName();
>>>>> > +      Diag(PIDecl->getLocation(), diag::note_property_declare);
>>>>> > +    }
>>>>> > +  }
>>>>> > +
>>>>> >   *isOverridingProperty = true;
>>>>> > -  // Make sure setter decl is synthesized, and added to primary
>>>>> class's list.
>>>>> > -  ProcessPropertyDecl(PIDecl, CCPrimary, PDecl, CDecl);
>>>>> > -  PDecl->setGetterMethodDecl(PIDecl->getGetterMethodDecl());
>>>>> > -  PDecl->setSetterMethodDecl(PIDecl->getSetterMethodDecl());
>>>>> > -  if (ASTMutationListener *L = Context.getASTMutationListener())
>>>>> > -    L->AddedObjCPropertyInClassExtension(PDecl, PIDecl, CDecl);
>>>>> > +
>>>>> > +  // Make sure setter decl is synthesized, and added to
>>>>> continuation class's list.
>>>>> > +  ProcessPropertyDecl(PDecl, CDecl, PIDecl, CDecl);
>>>>> >   return PDecl;
>>>>> > }
>>>>> >
>>>>> > @@ -1480,6 +1417,11 @@ static void CollectImmediateProperties(O
>>>>> >   if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
>>>>> {
>>>>> >     for (auto *Prop : IDecl->properties())
>>>>> >       PropMap[Prop->getIdentifier()] = Prop;
>>>>> > +
>>>>> > +    // Collect the properties from visible extensions.
>>>>> > +    for (auto *Ext : IDecl->visible_extensions())
>>>>> > +      CollectImmediateProperties(Ext, PropMap, SuperPropMap,
>>>>> IncludeProtocols);
>>>>> > +
>>>>> >     if (IncludeProtocols) {
>>>>> >       // Scan through class's protocols.
>>>>> >       for (auto *PI : IDecl->all_referenced_protocols())
>>>>> > @@ -1487,9 +1429,8 @@ static void CollectImmediateProperties(O
>>>>> >     }
>>>>> >   }
>>>>> >   if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
>>>>> {
>>>>> > -    if (!CATDecl->IsClassExtension())
>>>>> > -      for (auto *Prop : CATDecl->properties())
>>>>> > -        PropMap[Prop->getIdentifier()] = Prop;
>>>>> > +    for (auto *Prop : CATDecl->properties())
>>>>> > +      PropMap[Prop->getIdentifier()] = Prop;
>>>>> >     if (IncludeProtocols) {
>>>>> >       // Scan through class's protocols.
>>>>> >       for (auto *PI : CATDecl->protocols())
>>>>> > @@ -1549,6 +1490,14 @@ Sema::IvarBacksCurrentMethodAccessor(Obj
>>>>> >         (Property->getPropertyIvarDecl() == IV))
>>>>> >       return true;
>>>>> >   }
>>>>> > +  // Also look up property declaration in class extension whose one
>>>>> of its
>>>>> > +  // accessors is implemented by this method.
>>>>> > +  for (const auto *Ext : IFace->known_extensions())
>>>>> > +    for (const auto *Property : Ext->properties())
>>>>> > +      if ((Property->getGetterName() == IMD->getSelector() ||
>>>>> > +           Property->getSetterName() == IMD->getSelector()) &&
>>>>> > +          (Property->getPropertyIvarDecl() == IV))
>>>>> > +        return true;
>>>>> >   return false;
>>>>> > }
>>>>> >
>>>>> > @@ -1833,11 +1782,20 @@ void Sema::diagnoseNullResettableSynthes
>>>>> >
>>>>> > void
>>>>> > Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
>>>>> > -                                       ObjCContainerDecl* IDecl) {
>>>>> > +                                       ObjCInterfaceDecl* IDecl) {
>>>>> >   // Rules apply in non-GC mode only
>>>>> >   if (getLangOpts().getGC() != LangOptions::NonGC)
>>>>> >     return;
>>>>> > -  for (const auto *Property : IDecl->properties()) {
>>>>> > +  ObjCContainerDecl::PropertyMap PM;
>>>>> > +  for (auto *Prop : IDecl->properties())
>>>>> > +    PM[Prop->getIdentifier()] = Prop;
>>>>> > +  for (const auto *Ext : IDecl->known_extensions())
>>>>> > +    for (auto *Prop : Ext->properties())
>>>>> > +      PM[Prop->getIdentifier()] = Prop;
>>>>> > +
>>>>> > +    for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E
>>>>> = PM.end();
>>>>> > +         I != E; ++I) {
>>>>> > +    const ObjCPropertyDecl *Property = I->second;
>>>>> >     ObjCMethodDecl *GetterMethod = nullptr;
>>>>> >     ObjCMethodDecl *SetterMethod = nullptr;
>>>>> >     bool LookedUpGetterSetter = false;
>>>>> > @@ -1884,30 +1842,23 @@ Sema::AtomicPropertySetterGetterRules (O
>>>>> >           << Property->getIdentifier() << (GetterMethod != nullptr)
>>>>> >           << (SetterMethod != nullptr);
>>>>> >         // fixit stuff.
>>>>> > -        if (!AttributesAsWritten) {
>>>>> > -          if (Property->getLParenLoc().isValid()) {
>>>>> > -            // @property () ... case.
>>>>> > -            SourceRange PropSourceRange(Property->getAtLoc(),
>>>>> > -                                        Property->getLParenLoc());
>>>>> > -            Diag(Property->getLocation(),
>>>>> diag::note_atomic_property_fixup_suggest) <<
>>>>> > -              FixItHint::CreateReplacement(PropSourceRange,
>>>>> "@property (nonatomic");
>>>>> > -          }
>>>>> > -          else {
>>>>> > -            //@property id etc.
>>>>> > -            SourceLocation endLoc =
>>>>> > -
>>>>> Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
>>>>> > -            endLoc = endLoc.getLocWithOffset(-1);
>>>>> > -            SourceRange PropSourceRange(Property->getAtLoc(),
>>>>> endLoc);
>>>>> > -            Diag(Property->getLocation(),
>>>>> diag::note_atomic_property_fixup_suggest) <<
>>>>> > -              FixItHint::CreateReplacement(PropSourceRange,
>>>>> "@property (nonatomic) ");
>>>>> > -          }
>>>>> > -        }
>>>>> > -        else if (!(AttributesAsWritten &
>>>>> ObjCPropertyDecl::OBJC_PR_atomic)) {
>>>>> > +        if (Property->getLParenLoc().isValid() &&
>>>>> > +            !(AttributesAsWritten &
>>>>> ObjCPropertyDecl::OBJC_PR_atomic)) {
>>>>> >           // @property () ... case.
>>>>> > -          SourceLocation endLoc = Property->getLParenLoc();
>>>>> > -          SourceRange PropSourceRange(Property->getAtLoc(), endLoc);
>>>>> > -          Diag(Property->getLocation(),
>>>>> diag::note_atomic_property_fixup_suggest) <<
>>>>> > -           FixItHint::CreateReplacement(PropSourceRange, "@property
>>>>> (nonatomic, ");
>>>>> > +          SourceLocation AfterLParen =
>>>>> > +            getLocForEndOfToken(Property->getLParenLoc());
>>>>> > +          StringRef NonatomicStr = AttributesAsWritten? "nonatomic,
>>>>> "
>>>>> > +                                                      : "nonatomic";
>>>>> > +          Diag(Property->getLocation(),
>>>>> > +               diag::note_atomic_property_fixup_suggest)
>>>>> > +            << FixItHint::CreateInsertion(AfterLParen,
>>>>> NonatomicStr);
>>>>> > +        } else if (Property->getLParenLoc().isInvalid()) {
>>>>> > +          //@property id etc.
>>>>> > +          SourceLocation startLoc =
>>>>> > +
>>>>> Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
>>>>> > +          Diag(Property->getLocation(),
>>>>> > +               diag::note_atomic_property_fixup_suggest)
>>>>> > +            << FixItHint::CreateInsertion(startLoc, "(nonatomic) ");
>>>>> >         }
>>>>> >         else
>>>>> >           Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
>>>>> > @@ -2035,7 +1986,20 @@ void Sema::ProcessPropertyDecl(ObjCPrope
>>>>> >     return;
>>>>> >
>>>>> >   GetterMethod = CD->getInstanceMethod(property->getGetterName());
>>>>> > +  // if setter or getter is not found in class extension, it might
>>>>> be
>>>>> > +  // in the primary class.
>>>>> > +  if (!GetterMethod)
>>>>> > +    if (const ObjCCategoryDecl *CatDecl =
>>>>> dyn_cast<ObjCCategoryDecl>(CD))
>>>>> > +      if (CatDecl->IsClassExtension())
>>>>> > +        GetterMethod = CatDecl->getClassInterface()->
>>>>> > +
>>>>>  getInstanceMethod(property->getGetterName());
>>>>> > +
>>>>> >   SetterMethod = CD->getInstanceMethod(property->getSetterName());
>>>>> > +  if (!SetterMethod)
>>>>> > +    if (const ObjCCategoryDecl *CatDecl =
>>>>> dyn_cast<ObjCCategoryDecl>(CD))
>>>>> > +      if (CatDecl->IsClassExtension())
>>>>> > +        SetterMethod = CatDecl->getClassInterface()->
>>>>> > +
>>>>> getInstanceMethod(property->getSetterName());
>>>>> >   DiagnosePropertyAccessorMismatch(property, GetterMethod,
>>>>> >                                    property->getLocation());
>>>>> >
>>>>> > @@ -2068,9 +2032,7 @@ void Sema::ProcessPropertyDecl(ObjCPrope
>>>>> >     // No instance method of same name as property getter name was
>>>>> found.
>>>>> >     // Declare a getter method and add it to the list of methods
>>>>> >     // for this class.
>>>>> > -    SourceLocation Loc = redeclaredProperty ?
>>>>> > -      redeclaredProperty->getLocation() :
>>>>> > -      property->getLocation();
>>>>> > +    SourceLocation Loc = property->getLocation();
>>>>> >
>>>>> >     // If the property is null_resettable, the getter returns
>>>>> nonnull.
>>>>> >     QualType resultTy = property->getType();
>>>>> > @@ -2130,9 +2092,7 @@ void Sema::ProcessPropertyDecl(ObjCPrope
>>>>> >       // No instance method of same name as property setter name was
>>>>> found.
>>>>> >       // Declare a setter method and add it to the list of methods
>>>>> >       // for this class.
>>>>> > -      SourceLocation Loc = redeclaredProperty ?
>>>>> > -        redeclaredProperty->getLocation() :
>>>>> > -        property->getLocation();
>>>>> > +      SourceLocation Loc = property->getLocation();
>>>>> >
>>>>> >       SetterMethod =
>>>>> >         ObjCMethodDecl::Create(Context, Loc, Loc,
>>>>> >
>>>>> > Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
>>>>> > +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Nov  2 19:15:46
>>>>> 2015
>>>>> > @@ -5756,21 +5756,6 @@ void ASTWriter::AddedObjCCategoryToInter
>>>>> >     const_cast<ObjCInterfaceDecl *>(IFD->getDefinition()));
>>>>> > }
>>>>> >
>>>>> > -
>>>>> > -void ASTWriter::AddedObjCPropertyInClassExtension(const
>>>>> ObjCPropertyDecl *Prop,
>>>>> > -                                          const ObjCPropertyDecl
>>>>> *OrigProp,
>>>>> > -                                          const ObjCCategoryDecl
>>>>> *ClassExt) {
>>>>> > -  const ObjCInterfaceDecl *D = ClassExt->getClassInterface();
>>>>> > -  if (!D)
>>>>> > -    return;
>>>>> > -
>>>>> > -  assert(!WritingAST && "Already writing the AST!");
>>>>> > -  if (!D->isFromASTFile())
>>>>> > -    return; // Declaration not imported from PCH.
>>>>> > -
>>>>> > -  RewriteDecl(D);
>>>>> > -}
>>>>> > -
>>>>> > void ASTWriter::DeclarationMarkedUsed(const Decl *D) {
>>>>> >   assert(!WritingAST && "Already writing the AST!");
>>>>> >   if (!D->isFromASTFile())
>>>>> >
>>>>> > Modified: cfe/trunk/test/FixIt/atomic-property.m
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/atomic-property.m?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/test/FixIt/atomic-property.m (original)
>>>>> > +++ cfe/trunk/test/FixIt/atomic-property.m Mon Nov  2 19:15:46 2015
>>>>> > @@ -23,7 +23,7 @@
>>>>> > - (id) atomic_prop1 { return 0; }
>>>>> > @end
>>>>> >
>>>>> > -// CHECK: {4:1-4:10}:"@property (nonatomic) "
>>>>> > -// CHECK: {9:1-9:12}:"@property (nonatomic"
>>>>> > -// CHECK: {13:1-13:12}:"@property (nonatomic, "
>>>>> > +// CHECK-DAG: {4:11-4:11}:"(nonatomic) "
>>>>> > +// CHECK-DAG: {9:12-9:12}:"nonatomic"
>>>>> > +// CHECK-DAG: {13:12-13:12}:"nonatomic, "
>>>>> >
>>>>> >
>>>>> > Modified: cfe/trunk/test/Index/complete-kvc.m
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-kvc.m?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/test/Index/complete-kvc.m (original)
>>>>> > +++ cfe/trunk/test/Index/complete-kvc.m Mon Nov  2 19:15:46 2015
>>>>> > @@ -101,5 +101,5 @@ typedef signed char BOOL;
>>>>> >
>>>>> > // RUN: c-index-test -code-completion-at=%s:52:8 %s | FileCheck
>>>>> -check-prefix=CHECK-CC3 %s
>>>>> > // CHECK-CC3: ObjCInstanceMethodDecl:{TypedText countOfIntProperty}
>>>>> (55)
>>>>> > -// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText intProperty}
>>>>> (40)
>>>>> > +// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText intProperty}
>>>>> (42)
>>>>> > // CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText isIntProperty}
>>>>> (40)
>>>>> >
>>>>> > Modified: cfe/trunk/test/Modules/ModuleDebugInfo.m
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/ModuleDebugInfo.m?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/test/Modules/ModuleDebugInfo.m (original)
>>>>> > +++ cfe/trunk/test/Modules/ModuleDebugInfo.m Mon Nov  2 19:15:46 2015
>>>>> > @@ -33,7 +33,7 @@
>>>>> > // CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "InnerEnum"
>>>>> > // CHECK: !DISubprogram(name: "+[ObjCClass classMethod]"
>>>>> > // CHECK: !DISubprogram(name: "-[ObjCClass instanceMethodWithInt:]"
>>>>> > -// CHECK: !DISubprogram(name: "-[ categoryMethod]"
>>>>> > +// CHECK: !DISubprogram(name: "-[Category(Category) categoryMethod]"
>>>>> >
>>>>> > // MODULE-CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
>>>>> > // MODULE-CHECK-SAME:             scope: ![[MODULE:[0-9]+]],
>>>>> >
>>>>> > Modified: cfe/trunk/test/PCH/chain-categories.m
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/chain-categories.m?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/test/PCH/chain-categories.m (original)
>>>>> > +++ cfe/trunk/test/PCH/chain-categories.m Mon Nov  2 19:15:46 2015
>>>>> > @@ -16,6 +16,10 @@
>>>>> > - (void)finalize;
>>>>> > @end
>>>>> >
>>>>> > + at interface NSObject (Properties)
>>>>> > + at property (readonly,nonatomic) int intProp;
>>>>> > + at end
>>>>> > +
>>>>> >
>>>>> //===----------------------------------------------------------------------===//
>>>>> > #elif !defined(HEADER2)
>>>>> > #define HEADER2
>>>>> > @@ -34,6 +38,12 @@
>>>>> > -(void)extMeth;
>>>>> > @end
>>>>> >
>>>>> > + at interface NSObject ()
>>>>> > + at property (readwrite,nonatomic) int intProp;
>>>>> > + at end
>>>>> > +
>>>>> > + at class NSObject;
>>>>> > +
>>>>> >
>>>>> //===----------------------------------------------------------------------===//
>>>>> > #else
>>>>> >
>>>>> //===----------------------------------------------------------------------===//
>>>>> > @@ -47,6 +57,9 @@
>>>>> >
>>>>> > void test(NSObject *o) {
>>>>> >   [o extMeth];
>>>>> > +
>>>>> > +  // Make sure the property is treated as read-write.
>>>>> > +  o.intProp = 17;
>>>>> > }
>>>>> >
>>>>> >
>>>>> //===----------------------------------------------------------------------===//
>>>>> >
>>>>> > Modified: cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m
>>>>> (original)
>>>>> > +++ cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m Mon
>>>>> Nov  2 19:15:46 2015
>>>>> > @@ -129,10 +129,8 @@
>>>>> >
>>>>> > // read-only in class, read-write in class extension - might warn
>>>>> > @property(readonly) int GetSet_ReadWriteInExt;
>>>>> > - at property(readonly) int Get_ReadWriteInExt;  // expected-note
>>>>> {{property declared here}} \
>>>>> > -                                                // expected-note
>>>>> {{setter and getter must both be synthesized}}
>>>>> > - at property(readonly) int Set_ReadWriteInExt;  // expected-note
>>>>> {{property declared here}} \
>>>>> > -                                                // expected-note
>>>>> {{setter and getter must both be synthesized}}
>>>>> > + at property(readonly) int Get_ReadWriteInExt;
>>>>> > + at property(readonly) int Set_ReadWriteInExt;
>>>>> > @property(readonly) int None_ReadWriteInExt;
>>>>> > @property(nonatomic,readonly) int GetSet_Nonatomic_ReadWriteInExt;
>>>>> > @property(nonatomic,readonly) int Get_Nonatomic_ReadWriteInExt;
>>>>> > @@ -162,10 +160,8 @@
>>>>> > @property(nonatomic,readonly) int
>>>>> None_Nonatomic_ReadOnly_LateSynthesize;
>>>>> >
>>>>> > @property(readonly) int GetSet_ReadWriteInExt_LateSynthesize;
>>>>> > - at property(readonly) int Get_ReadWriteInExt_LateSynthesize;   //
>>>>> expected-note {{property declared here}} \
>>>>> > -                                                                //
>>>>> expected-note {{setter and getter must both be synthesized}}
>>>>> > - at property(readonly) int Set_ReadWriteInExt_LateSynthesize;   //
>>>>> expected-note {{property declared here}} \
>>>>> > -                                                                //
>>>>> expected-note {{setter and getter must both be synthesized}}
>>>>> > + at property(readonly) int Get_ReadWriteInExt_LateSynthesize;
>>>>> > + at property(readonly) int Set_ReadWriteInExt_LateSynthesize;
>>>>> > @property(readonly) int None_ReadWriteInExt_LateSynthesize;
>>>>> > @property(nonatomic,readonly) int
>>>>> GetSet_Nonatomic_ReadWriteInExt_LateSynthesize;
>>>>> > @property(nonatomic,readonly) int
>>>>> Get_Nonatomic_ReadWriteInExt_LateSynthesize;
>>>>> > @@ -207,8 +203,10 @@
>>>>> > @interface Foo ()
>>>>> >
>>>>> > @property(readwrite) int GetSet_ReadWriteInExt;
>>>>> > - at property(readwrite) int Get_ReadWriteInExt;
>>>>> > - at property(readwrite) int Set_ReadWriteInExt;
>>>>> > + at property(readwrite) int Get_ReadWriteInExt; // expected-note
>>>>> {{property declared here}} \
>>>>> > +                                             // expected-note
>>>>> {{setter and getter must both be synthesized}}
>>>>> > + at property(readwrite) int Set_ReadWriteInExt; // expected-note
>>>>> {{property declared here}} \
>>>>> > +                                             // expected-note
>>>>> {{setter and getter must both be synthesized}}
>>>>> > @property(readwrite) int None_ReadWriteInExt;
>>>>> > @property(nonatomic,readwrite) int GetSet_Nonatomic_ReadWriteInExt;
>>>>> > @property(nonatomic,readwrite) int Get_Nonatomic_ReadWriteInExt;
>>>>> > @@ -216,8 +214,10 @@
>>>>> > @property(nonatomic,readwrite) int None_Nonatomic_ReadWriteInExt;
>>>>> >
>>>>> > @property(readwrite) int GetSet_ReadWriteInExt_LateSynthesize;
>>>>> > - at property(readwrite) int Get_ReadWriteInExt_LateSynthesize;
>>>>> > - at property(readwrite) int Set_ReadWriteInExt_LateSynthesize;
>>>>> > + at property(readwrite) int Get_ReadWriteInExt_LateSynthesize;  //
>>>>> expected-note {{property declared here}} \
>>>>> > +                                                             //
>>>>> expected-note {{setter and getter must both be synthesized}}
>>>>> > + at property(readwrite) int Set_ReadWriteInExt_LateSynthesize; //
>>>>> expected-note {{property declared here}} \
>>>>> > +                                                            //
>>>>> expected-note {{setter and getter must both be synthesized}}
>>>>> > @property(readwrite) int None_ReadWriteInExt_LateSynthesize;
>>>>> > @property(nonatomic,readwrite) int
>>>>> GetSet_Nonatomic_ReadWriteInExt_LateSynthesize;
>>>>> > @property(nonatomic,readwrite) int
>>>>> Get_Nonatomic_ReadWriteInExt_LateSynthesize;
>>>>> >
>>>>> > Modified: cfe/trunk/test/SemaObjC/property-3.m
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-3.m?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/test/SemaObjC/property-3.m (original)
>>>>> > +++ cfe/trunk/test/SemaObjC/property-3.m Mon Nov  2 19:15:46 2015
>>>>> > @@ -29,5 +29,5 @@ typedef signed char BOOL;
>>>>> >
>>>>> > @interface EKCalendar ()  <EKProtocolMutableCalendar>
>>>>> > @property (nonatomic, assign) BOOL allowReminders;
>>>>> > - at property (nonatomic, assign) BOOL allowNonatomicProperty; //
>>>>> expected-warning {{'atomic' attribute on property 'allowNonatomicProperty'
>>>>> does not match the property inherited from 'EKProtocolCalendar'}}
>>>>> > + at property (nonatomic, assign) BOOL allowNonatomicProperty; //
>>>>> expected-warning {{'atomic' attribute on property 'allowNonatomicProperty'
>>>>> does not match the property inherited from EKProtocolCalendar}}
>>>>> > @end
>>>>> >
>>>>> > Modified: cfe/trunk/test/SemaObjC/property-in-class-extension-1.m
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-in-class-extension-1.m?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/test/SemaObjC/property-in-class-extension-1.m
>>>>> (original)
>>>>> > +++ cfe/trunk/test/SemaObjC/property-in-class-extension-1.m Mon Nov
>>>>> 2 19:15:46 2015
>>>>> > @@ -10,7 +10,7 @@
>>>>> >
>>>>> > @property (nonatomic, copy, readonly) NSString* matchingMemoryModel;
>>>>> >
>>>>> > - at property (nonatomic, retain, readonly) NSString*
>>>>> addingNoNewMemoryModel;
>>>>> > + at property (atomic, retain, readonly) NSString*
>>>>> addingNoNewMemoryModel;
>>>>> >
>>>>> > @property (readonly) NSString* none;
>>>>> > @property (readonly) NSString* none1;
>>>>> > @@ -50,10 +50,14 @@
>>>>> > // rdar://12214070
>>>>> > @interface radar12214070
>>>>> > @property (nonatomic, atomic, readonly) float propertyName; //
>>>>> expected-error {{property attributes 'atomic' and 'nonatomic' are mutually
>>>>> exclusive}}
>>>>> > +
>>>>> > + at property (nonatomic, readonly) float propertyName2; //
>>>>> expected-note {{property declared here}}
>>>>> > @end
>>>>> >
>>>>> > @interface radar12214070 ()
>>>>> > @property (atomic, nonatomic, readonly, readwrite) float
>>>>> propertyName; // expected-error {{property attributes 'readonly' and
>>>>> 'readwrite' are mutually exclusive}} \
>>>>> >               // expected-error {{property attributes 'atomic' and
>>>>> 'nonatomic' are mutually exclusive}}
>>>>> > +
>>>>> > + at property (atomic, readwrite) float propertyName2; //
>>>>> expected-warning {{'atomic' attribute on property 'propertyName2' does not
>>>>> match the property inherited from radar12214070}}
>>>>> > @end
>>>>> >
>>>>> >
>>>>> > Modified: cfe/trunk/test/SemaObjCXX/property-invalid-type.mm
>>>>> > URL:
>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/property-invalid-type.mm?rev=251874&r1=251873&r2=251874&view=diff
>>>>> >
>>>>> ==============================================================================
>>>>> > --- cfe/trunk/test/SemaObjCXX/property-invalid-type.mm (original)
>>>>> > +++ cfe/trunk/test/SemaObjCXX/property-invalid-type.mm Mon Nov  2
>>>>> 19:15:46 2015
>>>>> > @@ -13,11 +13,11 @@
>>>>> > @synthesize response;
>>>>> > - (void) foo :(A*) a   // expected-error {{expected a type}}
>>>>> > {
>>>>> > -  self.response = a;
>>>>> > +  self.response = a; // expected-error{{assigning to 'int *' from
>>>>> incompatible type 'id'}}
>>>>> > }
>>>>> > @end
>>>>> >
>>>>> > void foo(I *i)
>>>>> > {
>>>>> > -  i.helper;
>>>>> > +  i.helper; // expected-warning{{property access result unused -
>>>>> getters should not be used for side effects}}
>>>>> > }
>>>>> >
>>>>> >
>>>>> > _______________________________________________
>>>>> > cfe-commits mailing list
>>>>> > cfe-commits at lists.llvm.org
>>>>> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>>
>>>>> _______________________________________________
>>>>> cfe-commits mailing list
>>>>> cfe-commits at lists.llvm.org
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>>
>>>>
>>>>
>>>
>> <propregression.patch>
>>
>>
>>
> <prop.diff>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20151203/30280007/attachment-0001.html>
-------------- next part --------------
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp	(revision 254610)
+++ lib/CodeGen/CGDebugInfo.cpp	(working copy)
@@ -1791,7 +1791,7 @@
   }
 
   // Create entries for all of the properties.
-  for (const auto *PD : ID->properties()) {
+  auto AddProperty = [&](const ObjCPropertyDecl *PD) {
     SourceLocation Loc = PD->getLocation();
     llvm::DIFile *PUnit = getOrCreateFile(Loc);
     unsigned PLine = getLineNumber(Loc);
@@ -1805,6 +1805,21 @@
                                          : getSelectorName(PD->getSetterName()),
         PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit));
     EltTys.push_back(PropertyNode);
+  };
+  {
+    llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
+    for (const ObjCCategoryDecl *ClassExt : ID->known_extensions())
+      for (auto *PD : ClassExt->properties()) {
+        PropertySet.insert(PD->getIdentifier());
+        AddProperty(PD);
+      }
+    for (const auto *PD : ID->properties()) {
+      // Don't emit duplicate metadata for properties that were already in a
+      // class extension.
+      if (!PropertySet.insert(PD->getIdentifier()).second)
+        continue;
+      AddProperty(PD);
+    }
   }
 
   const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
Index: test/CodeGenObjC/debug-info-property-class-extension.m
===================================================================
--- test/CodeGenObjC/debug-info-property-class-extension.m	(revision 0)
+++ test/CodeGenObjC/debug-info-property-class-extension.m	(working copy)
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -S -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s
+
+// Checks debug info for properties from class extensions for a few cases.
+
+
+// Readonly property in interface made readwrite in a category, with @impl
+// The interesting bit is that when the ivar debug info is generated, the corresponding
+// property is looked up and also gets debug info. If the debug info from the interface's
+// declaration and from the ivar doesn't match, this will end up with two DIObjCProperty
+// entries which would be bad.
+ at interface FooROWithImpl
+// CHECK-NOT: !DIObjCProperty(name: "evolvingpropwithimpl"{{.*}}line: [[@LINE+1]]
+ at property (readonly) int evolvingpropwithimpl;
+ at end
+ at interface FooROWithImpl ()
+// CHECK: !DIObjCProperty(name: "evolvingpropwithimpl"{{.*}}line: [[@LINE+1]]
+ at property int evolvingpropwithimpl;
+ at end
+ at implementation FooROWithImpl
+ at synthesize evolvingpropwithimpl = _evolvingpropwithimpl;
+ at end
+
+
+// Simple property from a class extension:
+ at interface Foo
+ at end
+ at interface Foo()
+// CHECK: !DIObjCProperty(name: "myprop"{{.*}}line: [[@LINE+1]]
+ at property int myprop;
+ at end
+// There's intentionally no @implementation for Foo, because that would
+// generate debug info for the property via the backing ivar.
+
+
+// Readonly property in interface made readwrite in a category:
+ at interface FooRO
+// Shouldn't be here but in the class extension below.
+// CHECK-NOT: !DIObjCProperty(name: "evolvingprop"{{.*}}line: [[@LINE+1]]
+ at property (readonly) int evolvingprop;
+ at end
+ at interface FooRO ()
+// CHECK: !DIObjCProperty(name: "evolvingprop"{{.*}}line: [[@LINE+1]]
+ at property int evolvingprop;
+ at end
+
+
+// This references types in this file to force emission of their debug info.
+void foo(Foo *f, FooRO *g, FooROWithImpl* h) { }


More information about the cfe-commits mailing list