r241542 - Handle Objective-C type arguments.

Douglas Gregor dgregor at apple.com
Mon Jul 6 20:57:36 PDT 2015


Author: dgregor
Date: Mon Jul  6 22:57:35 2015
New Revision: 241542

URL: http://llvm.org/viewvc/llvm-project?rev=241542&view=rev
Log:
Handle Objective-C type arguments.

Objective-C type arguments can be provided in angle brackets following
an Objective-C interface type. Syntactically, this is the same
position as one would provide protocol qualifiers (e.g.,
id<NSCopying>), so parse both together and let Sema sort out the
ambiguous cases. This applies both when parsing types and when parsing
the superclass of an Objective-C class, which can now be a specialized
type (e.g., NSMutableArray<T> inherits from NSArray<T>).

Check Objective-C type arguments against the type parameters of the
corresponding class. Verify the length of the type argument list and
that each type argument satisfies the corresponding bound.

Specializations of parameterized Objective-C classes are represented
in the type system as distinct types. Both specialized types (e.g.,
NSArray<NSString *> *) and unspecialized types (NSArray *) are
represented, separately.

Added:
    cfe/trunk/test/Index/annotate-parameterized-classes.m
    cfe/trunk/test/SemaObjCXX/parameterized_classes.mm
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/AST/TypeLoc.h
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/ASTDiagnostic.cpp
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclObjC.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypeLoc.cpp
    cfe/trunk/lib/AST/TypePrinter.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/lib/Sema/DeclSpec.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/Index/complete-method-decls.m
    cfe/trunk/test/PCH/objc_parameterized_classes.m
    cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm
    cfe/trunk/test/SemaObjC/interface-1.m
    cfe/trunk/test/SemaObjC/parameterized_classes.m
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/CursorVisitor.h

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Mon Jul  6 22:57:35 2015
@@ -236,6 +236,12 @@ class ASTContext : public RefCountedBase
   QualType ObjCClassRedefinitionType;
   QualType ObjCSelRedefinitionType;
 
+  /// The identifier 'NSObject'.
+  IdentifierInfo *NSObjectName = nullptr;
+
+  /// The identifier 'NSCopying'.
+  IdentifierInfo *NSCopyingName = nullptr;
+
   QualType ObjCConstantStringType;
   mutable RecordDecl *CFConstantStringTypeDecl;
   
@@ -1189,9 +1195,14 @@ public:
   QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
                                 ObjCInterfaceDecl *PrevDecl = nullptr) const;
 
+  /// Legacy interface: cannot provide type arguments.
   QualType getObjCObjectType(QualType Base,
                              ObjCProtocolDecl * const *Protocols,
                              unsigned NumProtocols) const;
+
+  QualType getObjCObjectType(QualType Base,
+                             ArrayRef<QualType> typeArgs,
+                             ArrayRef<ObjCProtocolDecl *> protocols) const;
   
   bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
   /// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
@@ -1351,6 +1362,24 @@ public:
     ObjCSelRedefinitionType = RedefType;
   }
 
+  /// Retrieve the identifier 'NSObject'.
+  IdentifierInfo *getNSObjectName() {
+    if (!NSObjectName) {
+      NSObjectName = &Idents.get("NSObject");
+    }
+
+    return NSObjectName;
+  }
+
+  /// Retrieve the identifier 'NSCopying'.
+  IdentifierInfo *getNSCopyingName() {
+    if (!NSCopyingName) {
+      NSCopyingName = &Idents.get("NSCopying");
+    }
+
+    return NSCopyingName;
+  }
+
   /// \brief Retrieve the Objective-C "instancetype" type, if already known;
   /// otherwise, returns a NULL type;
   QualType getObjCInstanceType() {

Modified: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h Mon Jul  6 22:57:35 2015
@@ -940,6 +940,8 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, {
   // type is itself.
   if (T->getBaseType().getTypePtr() != T)
     TRY_TO(TraverseType(T->getBaseType()));
+  for (auto typeArg : T->getTypeArgsAsWritten())
+    TRY_TO(TraverseType(typeArg));
 })
 
 DEF_TRAVERSE_TYPE(ObjCObjectPointerType,
@@ -1166,6 +1168,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
   // type is itself.
   if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr())
     TRY_TO(TraverseTypeLoc(TL.getBaseLoc()));
+  for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
+    TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc()));
 })
 
 DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType,
@@ -1325,7 +1329,10 @@ DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {//
     for (auto typeParam : *typeParamList)
       TRY_TO(TraverseObjCTypeParamDecl(typeParam));
   }
-  return true;
+
+  if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) {
+    TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc()));
+  }
 })
 
 DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Mon Jul  6 22:57:35 2015
@@ -794,9 +794,9 @@ class ObjCInterfaceDecl : public ObjCCon
     /// declaration.
     ObjCInterfaceDecl *Definition;
     
-    /// Class's super class.
-    ObjCInterfaceDecl *SuperClass;
-
+    /// When non-null, this is always an ObjCObjectType.
+    TypeSourceInfo *SuperClassTInfo;
+    
     /// Protocols referenced in the \@interface  declaration
     ObjCProtocolList ReferencedProtocols;
 
@@ -837,16 +837,13 @@ class ObjCInterfaceDecl : public ObjCCon
     };
     /// One of the \c InheritedDesignatedInitializersState enumeratos.
     mutable unsigned InheritedDesignatedInitializers : 2;
-
-    /// \brief The location of the superclass, if any.
-    SourceLocation SuperClassLoc;
     
     /// \brief The location of the last location in this declaration, before
     /// the properties/methods. For example, this will be the '>', '}', or 
     /// identifier, 
     SourceLocation EndLoc; 
 
-    DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(), 
+    DefinitionData() : Definition(), SuperClassTInfo(), CategoryList(), IvarList(), 
                        ExternallyCompleted(),
                        IvarListMissingImplementation(true),
                        HasDesignatedInitializers(),
@@ -903,8 +900,8 @@ public:
   /// Retrieve the type parameters of this class.
   ///
   /// This function looks for a type parameter list for the given
-  /// class; if the class has been declared (with @class) but not
-  /// defined (with @interface), it will search for a declaration that
+  /// class; if the class has been declared (with \c \@class) but not
+  /// defined (with \c \@interface), it will search for a declaration that
   /// has type parameters, skipping any declarations that do not.
   ObjCTypeParamList *getTypeParamList() const;
 
@@ -1160,7 +1157,16 @@ public:
   /// a forward declaration (\@class) to a definition (\@interface).
   void startDefinition();
   
-  ObjCInterfaceDecl *getSuperClass() const {
+  /// Retrieve the superclass type.
+  const ObjCObjectType *getSuperClassType() const {
+    if (TypeSourceInfo *TInfo = getSuperClassTInfo())
+      return TInfo->getType()->castAs<ObjCObjectType>();
+
+    return nullptr;
+  }
+
+  // Retrieve the type source information for the superclass.
+  TypeSourceInfo *getSuperClassTInfo() const {
     // FIXME: Should make sure no callers ever do this.
     if (!hasDefinition())
       return nullptr;
@@ -1168,13 +1174,15 @@ public:
     if (data().ExternallyCompleted)
       LoadExternalDefinition();
 
-    return data().SuperClass;
+    return data().SuperClassTInfo;
   }
 
-  void setSuperClass(ObjCInterfaceDecl * superCls) { 
-    data().SuperClass = 
-      (superCls && superCls->hasDefinition()) ? superCls->getDefinition() 
-                                              : superCls; 
+  // Retrieve the declaration for the superclass of this class, which
+  // does not include any type arguments that apply to the superclass.
+  ObjCInterfaceDecl *getSuperClass() const;
+
+  void setSuperClass(TypeSourceInfo *superClass) { 
+    data().SuperClassTInfo = superClass;
   }
 
   /// \brief Iterator that walks over the list of categories, filtering out
@@ -1466,8 +1474,8 @@ public:
                           
   void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; }
 
-  void setSuperClassLoc(SourceLocation Loc) { data().SuperClassLoc = Loc; }
-  SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; }
+  /// Retrieve the starting location of the superclass.
+  SourceLocation getSuperClassLoc() const;
 
   /// isImplicitInterfaceDecl - check that this is an implicitly declared
   /// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Mon Jul  6 22:57:35 2015
@@ -1008,6 +1008,8 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, {
   // type is itself.
   if (T->getBaseType().getTypePtr() != T)
     TRY_TO(TraverseType(T->getBaseType()));
+  for (auto typeArg : T->getTypeArgsAsWritten())
+    TRY_TO(TraverseType(typeArg));
 })
 
 DEF_TRAVERSE_TYPE(ObjCObjectPointerType,
@@ -1234,6 +1236,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
   // type is itself.
   if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr())
     TRY_TO(TraverseTypeLoc(TL.getBaseLoc()));
+  for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
+    TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc()));
 })
 
 DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType,
@@ -1399,6 +1403,10 @@ DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {//
     for (auto typeParam : *typeParamList)
       TRY_TO(TraverseObjCTypeParamDecl(typeParam));
   }
+
+  if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) {
+    TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc()));
+  }
 })
 
 DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Jul  6 22:57:35 2015
@@ -1288,10 +1288,14 @@ protected:
 
     unsigned : NumTypeBits;
 
+    /// The number of type arguments stored directly on this object type.
+    unsigned NumTypeArgs : 7;
+
     /// NumProtocols - The number of protocols stored directly on this
     /// object type.
-    unsigned NumProtocols : 32 - NumTypeBits;
+    unsigned NumProtocols : 7;
   };
+  static_assert(NumTypeBits + 7 + 7 <= 32, "Does not fit in an unsigned");
 
   class ReferenceTypeBitfields {
     friend class ReferenceType;
@@ -1586,6 +1590,7 @@ public:
   bool isObjCObjectOrInterfaceType() const;
   bool isObjCIdType() const;                    // id
   bool isObjCClassType() const;                 // Class
+  bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const;
   bool isObjCSelType() const;                 // Class
   bool isObjCBuiltinType() const;               // 'id' or 'Class'
   bool isObjCARCBridgableType() const;
@@ -4369,19 +4374,25 @@ public:
 };
 
 /// ObjCObjectType - Represents a class type in Objective C.
-/// Every Objective C type is a combination of a base type and a
-/// list of protocols.
+///
+/// Every Objective C type is a combination of a base type, a set of
+/// type arguments (optional, for parameterized classes) and a list of
+/// protocols.
 ///
 /// Given the following declarations:
 /// \code
-///   \@class C;
+///   \@class C<T>;
 ///   \@protocol P;
 /// \endcode
 ///
 /// 'C' is an ObjCInterfaceType C.  It is sugar for an ObjCObjectType
 /// with base C and no protocols.
 ///
-/// 'C<P>' is an ObjCObjectType with base C and protocol list [P].
+/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P].
+/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no 
+/// protocol list.
+/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments 'C*',
+/// and protocol list [P].
 ///
 /// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose
 /// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType
@@ -4391,8 +4402,10 @@ public:
 /// with base BuiltinType::ObjCIdType and protocol list [P].  Eventually
 /// this should get its own sugar class to better represent the source.
 class ObjCObjectType : public Type {
-  // ObjCObjectType.NumProtocols - the number of protocols stored
+  // ObjCObjectType.NumTypeArgs - the number of type arguments stored
   // after the ObjCObjectPointerType node.
+  // ObjCObjectType.NumProtocols - the number of protocols stored
+  // after the type arguments of ObjCObjectPointerType node.
   //
   // These protocols are those written directly on the type.  If
   // protocol qualifiers ever become additive, the iterators will need
@@ -4408,17 +4421,24 @@ class ObjCObjectType : public Type {
     return const_cast<ObjCObjectType*>(this)->getProtocolStorage();
   }
 
+  QualType *getTypeArgStorage();
+  const QualType *getTypeArgStorage() const {
+    return const_cast<ObjCObjectType *>(this)->getTypeArgStorage();
+  }
+
   ObjCProtocolDecl **getProtocolStorage();
 
 protected:
   ObjCObjectType(QualType Canonical, QualType Base,
-                 ObjCProtocolDecl * const *Protocols, unsigned NumProtocols);
+                 ArrayRef<QualType> typeArgs,
+                 ArrayRef<ObjCProtocolDecl *> protocols);
 
   enum Nonce_ObjCInterface { Nonce_ObjCInterface };
   ObjCObjectType(enum Nonce_ObjCInterface)
         : Type(ObjCInterface, QualType(), false, false, false, false),
       BaseType(QualType(this_(), 0)) {
     ObjCObjectTypeBits.NumProtocols = 0;
+    ObjCObjectTypeBits.NumTypeArgs = 0;
   }
 
 public:
@@ -4452,6 +4472,33 @@ public:
   /// really is an interface.
   ObjCInterfaceDecl *getInterface() const;
 
+  /// Determine whether this object type is "specialized", meaning
+  /// that it has type arguments.
+  bool isSpecialized() const;
+
+  /// Determine whether this object type was written with type arguments.
+  bool isSpecializedAsWritten() const { 
+    return ObjCObjectTypeBits.NumTypeArgs > 0; 
+  }
+
+  /// Determine whether this object type is "unspecialized", meaning
+  /// that it has no type arguments.
+  bool isUnspecialized() const { return !isSpecialized(); }
+
+  /// Determine whether this object type is "unspecialized" as
+  /// written, meaning that it has no type arguments.
+  bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); }
+
+  /// Retrieve the type arguments of this object type (semantically).
+  ArrayRef<QualType> getTypeArgs() const;
+
+  /// Retrieve the type arguments of this object type as they were
+  /// written.
+  ArrayRef<QualType> getTypeArgsAsWritten() const { 
+    return ArrayRef<QualType>(getTypeArgStorage(), 
+                              ObjCObjectTypeBits.NumTypeArgs);
+  }
+
   typedef ObjCProtocolDecl * const *qual_iterator;
   typedef llvm::iterator_range<qual_iterator> qual_range;
 
@@ -4491,21 +4538,25 @@ class ObjCObjectTypeImpl : public ObjCOb
   // will need to be modified.
 
   ObjCObjectTypeImpl(QualType Canonical, QualType Base,
-                     ObjCProtocolDecl * const *Protocols,
-                     unsigned NumProtocols)
-    : ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {}
+                     ArrayRef<QualType> typeArgs,
+                     ArrayRef<ObjCProtocolDecl *> protocols)
+    : ObjCObjectType(Canonical, Base, typeArgs, protocols) {}
 
 public:
   void Profile(llvm::FoldingSetNodeID &ID);
   static void Profile(llvm::FoldingSetNodeID &ID,
                       QualType Base,
-                      ObjCProtocolDecl *const *protocols,
-                      unsigned NumProtocols);
+                      ArrayRef<QualType> typeArgs,
+                      ArrayRef<ObjCProtocolDecl *> protocols);
 };
 
+inline QualType *ObjCObjectType::getTypeArgStorage() {
+  return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1);
+}
+
 inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() {
-  return reinterpret_cast<ObjCProtocolDecl**>(
-            static_cast<ObjCObjectTypeImpl*>(this) + 1);
+    return reinterpret_cast<ObjCProtocolDecl**>(
+             getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs);
 }
 
 /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
@@ -4556,9 +4607,14 @@ public:
 };
 
 inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const {
-  if (const ObjCInterfaceType *T =
-        getBaseType()->getAs<ObjCInterfaceType>())
-    return T->getDecl();
+  QualType baseType = getBaseType();
+  while (const ObjCObjectType *ObjT = baseType->getAs<ObjCObjectType>()) {
+    if (const ObjCInterfaceType *T = dyn_cast<ObjCInterfaceType>(ObjT))
+      return T->getDecl();
+
+    baseType = ObjT->getBaseType();
+  }
+
   return nullptr;
 }
 
@@ -4653,6 +4709,31 @@ public:
     return getObjectType()->isObjCQualifiedClass();
   }
 
+  /// Whether this type is specialized, meaning that it has type arguments.
+  bool isSpecialized() const { return getObjectType()->isSpecialized(); }
+
+  /// Whether this type is specialized, meaning that it has type arguments.
+  bool isSpecializedAsWritten() const { 
+    return getObjectType()->isSpecializedAsWritten(); 
+  }
+  
+  /// Whether this type is unspecialized, meaning that is has no type arguments.
+  bool isUnspecialized() const { return getObjectType()->isUnspecialized(); }
+
+  /// Determine whether this object type is "unspecialized" as
+  /// written, meaning that it has no type arguments.
+  bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); }
+
+  /// Retrieve the type arguments for this type.
+  ArrayRef<QualType> getTypeArgs() const { 
+    return getObjectType()->getTypeArgs(); 
+  }
+
+  /// Retrieve the type arguments for this type.
+  ArrayRef<QualType> getTypeArgsAsWritten() const { 
+    return getObjectType()->getTypeArgsAsWritten(); 
+  }
+
   /// An iterator over the qualifiers on the object type.  Provided
   /// for convenience.  This will always iterate over the full set of
   /// protocols on a type, not just those provided directly.

Modified: cfe/trunk/include/clang/AST/TypeLoc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeLoc.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TypeLoc.h (original)
+++ cfe/trunk/include/clang/AST/TypeLoc.h Mon Jul  6 22:57:35 2015
@@ -799,9 +799,11 @@ public:
 };
 
 
-struct ObjCProtocolListLocInfo {
-  SourceLocation LAngleLoc;
-  SourceLocation RAngleLoc;
+struct ObjCObjectTypeLocInfo {
+  SourceLocation TypeArgsLAngleLoc;
+  SourceLocation TypeArgsRAngleLoc;
+  SourceLocation ProtocolLAngleLoc;
+  SourceLocation ProtocolRAngleLoc;
   bool HasBaseTypeAsWritten;
 };
 
@@ -813,25 +815,59 @@ struct ObjCProtocolListLocInfo {
 class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
                                                  ObjCObjectTypeLoc,
                                                  ObjCObjectType,
-                                                 ObjCProtocolListLocInfo> {
-  // SourceLocations are stored after Info, one for each Protocol.
+                                                 ObjCObjectTypeLocInfo> {
+  // TypeSourceInfo*'s are stored after Info, one for each type argument.
+  TypeSourceInfo **getTypeArgLocArray() const {
+    return (TypeSourceInfo**)this->getExtraLocalData();
+  }
+
+  // SourceLocations are stored after the type argument information, one for 
+  // each Protocol.
   SourceLocation *getProtocolLocArray() const {
-    return (SourceLocation*) this->getExtraLocalData();
+    return (SourceLocation*)(getTypeArgLocArray() + getNumTypeArgs());
   }
 
 public:
-  SourceLocation getLAngleLoc() const {
-    return this->getLocalData()->LAngleLoc;
+  SourceLocation getTypeArgsLAngleLoc() const {
+    return this->getLocalData()->TypeArgsLAngleLoc;
+  }
+  void setTypeArgsLAngleLoc(SourceLocation Loc) {
+    this->getLocalData()->TypeArgsLAngleLoc = Loc;
+  }
+
+  SourceLocation getTypeArgsRAngleLoc() const {
+    return this->getLocalData()->TypeArgsRAngleLoc;
+  }
+  void setTypeArgsRAngleLoc(SourceLocation Loc) {
+    this->getLocalData()->TypeArgsRAngleLoc = Loc;
   }
-  void setLAngleLoc(SourceLocation Loc) {
-    this->getLocalData()->LAngleLoc = Loc;
+
+  unsigned getNumTypeArgs() const {
+    return this->getTypePtr()->getTypeArgsAsWritten().size();
   }
 
-  SourceLocation getRAngleLoc() const {
-    return this->getLocalData()->RAngleLoc;
+  TypeSourceInfo *getTypeArgTInfo(unsigned i) const {
+    assert(i < getNumTypeArgs() && "Index is out of bounds!");
+    return getTypeArgLocArray()[i];
   }
-  void setRAngleLoc(SourceLocation Loc) {
-    this->getLocalData()->RAngleLoc = Loc;
+
+  void setTypeArgTInfo(unsigned i, TypeSourceInfo *TInfo) {
+    assert(i < getNumTypeArgs() && "Index is out of bounds!");
+    getTypeArgLocArray()[i] = TInfo;
+  }
+
+  SourceLocation getProtocolLAngleLoc() const {
+    return this->getLocalData()->ProtocolLAngleLoc;
+  }
+  void setProtocolLAngleLoc(SourceLocation Loc) {
+    this->getLocalData()->ProtocolLAngleLoc = Loc;
+  }
+
+  SourceLocation getProtocolRAngleLoc() const {
+    return this->getLocalData()->ProtocolRAngleLoc;
+  }
+  void setProtocolRAngleLoc(SourceLocation Loc) {
+    this->getLocalData()->ProtocolRAngleLoc = Loc;
   }
 
   unsigned getNumProtocols() const {
@@ -865,23 +901,26 @@ public:
   }
 
   SourceRange getLocalSourceRange() const {
-    return SourceRange(getLAngleLoc(), getRAngleLoc());
+    SourceLocation start = getTypeArgsLAngleLoc();
+    if (start.isInvalid())
+      start = getProtocolLAngleLoc();
+    SourceLocation end = getProtocolRAngleLoc();
+    if (end.isInvalid())
+      end = getTypeArgsRAngleLoc();
+    return SourceRange(start, end);
   }
 
-  void initializeLocal(ASTContext &Context, SourceLocation Loc) {
-    setHasBaseTypeAsWritten(true);
-    setLAngleLoc(Loc);
-    setRAngleLoc(Loc);
-    for (unsigned i = 0, e = getNumProtocols(); i != e; ++i)
-      setProtocolLoc(i, Loc);
-  }
+  void initializeLocal(ASTContext &Context, SourceLocation Loc);
 
   unsigned getExtraLocalDataSize() const {
-    return this->getNumProtocols() * sizeof(SourceLocation);
+    return this->getNumTypeArgs() * sizeof(TypeSourceInfo *)
+         + this->getNumProtocols() * sizeof(SourceLocation);
   }
 
   unsigned getExtraLocalDataAlignment() const {
-    return llvm::alignOf<SourceLocation>();
+    static_assert(alignof(ObjCObjectTypeLoc) >= alignof(TypeSourceInfo *),
+                  "not enough alignment for tail-allocated data");
+    return llvm::alignOf<TypeSourceInfo *>();
   }
 
   QualType getInnerType() const {

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Jul  6 22:57:35 2015
@@ -1022,12 +1022,11 @@ let CategoryName = "Generics Issue" in {
 def err_objc_expected_type_parameter : Error<
   "expected type parameter name">;
 
-def err_objc_parameterized_class_without_base : Error<
-  "parameterized Objective-C class %0 must have a superclass">;
-
 def err_objc_parameterized_implementation : Error<
   "@implementation cannot have type parameters">;
 
+def err_objc_type_args_after_protocols : Error<
+  "protocol qualifiers must precede type arguments">;
 }
 
 } // end of Parser diagnostics

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul  6 22:57:35 2015
@@ -7780,6 +7780,36 @@ def err_objc_parameterized_forward_class
 def err_objc_parameterized_forward_class_first : Error<
   "class %0 previously declared with type parameters">;
 
+def err_objc_type_arg_missing_star : Error<
+  "type argument %0 must be a pointer (requires a '*')">;
+
+def err_objc_type_arg_missing : Error<
+  "no type or protocol named %0">;
+
+def err_objc_protocol_suggest : Error<
+  "no protocol named %0: did you mean %1?">;
+
+def err_objc_type_args_and_protocols : Error<
+  "angle brackets contain both a %select{type|protocol}0 (%1) and a "
+  "%select{protocol|type}0 (%2)">;
+
+def err_objc_type_args_non_class : Error<
+  "type arguments cannot be applied to non-class type %0">;
+
+def err_objc_type_args_non_parameterized_class : Error<
+  "type arguments cannot be applied to non-parameterized class %0">;
+
+def err_objc_type_args_specialized_class : Error<
+  "type arguments cannot be applied to already-specialized class type %0">;
+
+def err_objc_type_args_wrong_arity : Error<
+  "too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">;
 }
 
+def err_objc_type_arg_not_id_compatible : Error<
+  "type argument %0 is neither an Objective-C object nor a block type">;
+
+def err_objc_type_arg_does_not_match_bound : Error<
+  "type argument %0 does not satisy the bound (%1) of type parameter %2">;
+
 } // end of sema component.

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul  6 22:57:35 2015
@@ -1269,6 +1269,8 @@ private:
                                    SourceLocation &LAngleLoc,
                                    SourceLocation &EndProtoLoc);
   bool ParseObjCProtocolQualifiers(DeclSpec &DS);
+  void ParseObjCTypeArgsOrProtocolQualifiers(DeclSpec &DS,
+                                             bool warnOnIncompleteProtocols);
   void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
                                   Decl *CDecl);
   DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc,

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Jul  6 22:57:35 2015
@@ -373,6 +373,14 @@ private:
   // Scope specifier for the type spec, if applicable.
   CXXScopeSpec TypeScope;
 
+  /// List of Objective-C type arguments, e.g., in \c NSArray<NSView *>.
+  ArrayRef<ParsedType> ObjCTypeArgs;
+
+  /// Location of the '<' that starts a list of Objective-C type arguments.
+  SourceLocation ObjCTypeArgsLAngleLoc;
+  /// Location of the '>' that ends a list of Objective-C type arguments.
+  SourceLocation ObjCTypeArgsRAngleLoc;
+
   // List of protocol qualifiers for objective-c classes.  Used for
   // protocol-qualified interfaces "NString<foo>" and protocol-qualified id
   // "id<foo>".
@@ -449,6 +457,7 @@ public:
       ObjCQualifiers(nullptr) {
   }
   ~DeclSpec() {
+    delete [] ObjCTypeArgs.data();
     delete [] ProtocolQualifiers;
     delete [] ProtocolLocs;
   }
@@ -751,6 +760,25 @@ public:
     Attrs.takeAllFrom(attrs);
   }
 
+  /// Determine whether the declaration specifiers contain Objective-C
+  /// type arguments.
+  bool hasObjCTypeArgs() const { return !ObjCTypeArgs.empty(); }
+
+  ArrayRef<ParsedType> getObjCTypeArgs() const { return ObjCTypeArgs; }
+  SourceLocation getObjCTypeArgsLAngleLoc() const {
+    return ObjCTypeArgsLAngleLoc;
+  }
+  SourceLocation getObjCTypeArgsRAngleLoc() const {
+    return ObjCTypeArgsRAngleLoc;
+  }
+  SourceRange getObjCTypeArgsRange() const {
+    return SourceRange(ObjCTypeArgsLAngleLoc, ObjCTypeArgsRAngleLoc);
+  }
+
+  void setObjCTypeArgs(SourceLocation lAngleLoc,
+                       ArrayRef<ParsedType> args,
+                       SourceLocation rAngleLoc);
+
   typedef Decl * const *ProtocolQualifierListTy;
   ProtocolQualifierListTy getProtocolQualifiers() const {
     return ProtocolQualifiers;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul  6 22:57:35 2015
@@ -7098,17 +7098,30 @@ public:
                                             SourceLocation rAngleLoc);
   void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList);
 
-  Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+  Decl *ActOnStartClassInterface(Scope *S,
+                                 SourceLocation AtInterfaceLoc,
                                  IdentifierInfo *ClassName,
                                  SourceLocation ClassLoc,
                                  ObjCTypeParamList *typeParamList,
                                  IdentifierInfo *SuperName,
                                  SourceLocation SuperLoc,
+                                 ArrayRef<ParsedType> SuperTypeArgs,
+                                 SourceRange SuperTypeArgsRange,
                                  Decl * const *ProtoRefs,
                                  unsigned NumProtoRefs,
                                  const SourceLocation *ProtoLocs,
                                  SourceLocation EndProtoLoc,
                                  AttributeList *AttrList);
+    
+  void ActOnSuperClassOfClassInterface(Scope *S,
+                                       SourceLocation AtInterfaceLoc,
+                                       ObjCInterfaceDecl *IDecl,
+                                       IdentifierInfo *ClassName,
+                                       SourceLocation ClassLoc,
+                                       IdentifierInfo *SuperName,
+                                       SourceLocation SuperLoc,
+                                       ArrayRef<ParsedType> SuperTypeArgs,
+                                       SourceRange SuperTypeArgsRange);
   
   void ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs,
                                IdentifierInfo *SuperName,
@@ -7174,6 +7187,19 @@ public:
                                unsigned NumProtocols,
                                SmallVectorImpl<Decl *> &Protocols);
 
+  /// Given a list of identifiers (and their locations), resolve the
+  /// names to either Objective-C protocol qualifiers or type
+  /// arguments, as appropriate. The result will be attached to the
+  /// given declaration specifiers.
+  void actOnObjCTypeArgsOrProtocolQualifiers(
+         Scope *S,
+         DeclSpec &DS,
+         SourceLocation lAngleLoc,
+         ArrayRef<IdentifierInfo *> identifiers,
+         ArrayRef<SourceLocation> identifierLocs,
+         SourceLocation rAngleLoc,
+         bool warnOnIncompleteProtocols);
+
   /// Ensure attributes are consistent with type.
   /// \param [in, out] Attributes The attributes to check; they will
   /// be modified to be consistent with \p PropertyTy.

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Jul  6 22:57:35 2015
@@ -3618,45 +3618,85 @@ static void SortAndUniqueProtocols(ObjCP
 QualType ASTContext::getObjCObjectType(QualType BaseType,
                                        ObjCProtocolDecl * const *Protocols,
                                        unsigned NumProtocols) const {
-  // If the base type is an interface and there aren't any protocols
-  // to add, then the interface type will do just fine.
-  if (!NumProtocols && isa<ObjCInterfaceType>(BaseType))
-    return BaseType;
+  return getObjCObjectType(BaseType, { },
+                           llvm::makeArrayRef(Protocols, NumProtocols));
+}
+
+QualType ASTContext::getObjCObjectType(
+           QualType baseType,
+           ArrayRef<QualType> typeArgs,
+           ArrayRef<ObjCProtocolDecl *> protocols) const {
+  // If the base type is an interface and there aren't any protocols or
+  // type arguments to add, then the interface type will do just fine.
+  if (typeArgs.empty() && protocols.empty() && isa<ObjCInterfaceType>(baseType))
+    return baseType;
 
   // Look in the folding set for an existing type.
   llvm::FoldingSetNodeID ID;
-  ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols);
+  ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols);
   void *InsertPos = nullptr;
   if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos))
     return QualType(QT, 0);
 
-  // Build the canonical type, which has the canonical base type and
-  // a sorted-and-uniqued list of protocols.
-  QualType Canonical;
-  bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols);
-  if (!ProtocolsSorted || !BaseType.isCanonical()) {
-    if (!ProtocolsSorted) {
-      SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
-                                                     Protocols + NumProtocols);
-      unsigned UniqueCount = NumProtocols;
-
-      SortAndUniqueProtocols(&Sorted[0], UniqueCount);
-      Canonical = getObjCObjectType(getCanonicalType(BaseType),
-                                    &Sorted[0], UniqueCount);
+  // Determine the type arguments to be used for canonicalization,
+  // which may be explicitly specified here or written on the base
+  // type.
+  ArrayRef<QualType> effectiveTypeArgs = typeArgs;
+  if (effectiveTypeArgs.empty()) {
+    if (auto baseObject = baseType->getAs<ObjCObjectType>())
+      effectiveTypeArgs = baseObject->getTypeArgs();
+  }
+
+  // Build the canonical type, which has the canonical base type and a
+  // sorted-and-uniqued list of protocols and the type arguments
+  // canonicalized.
+  QualType canonical;
+  bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(),
+                                          effectiveTypeArgs.end(),
+                                          [&](QualType type) {
+                                            return type.isCanonical();
+                                          });
+  bool protocolsSorted = areSortedAndUniqued(protocols.data(),
+                                             protocols.size());
+  if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) {
+    // Determine the canonical type arguments.
+    ArrayRef<QualType> canonTypeArgs;
+    SmallVector<QualType, 4> canonTypeArgsVec;
+    if (!typeArgsAreCanonical) {
+      canonTypeArgsVec.reserve(effectiveTypeArgs.size());
+      for (auto typeArg : effectiveTypeArgs)
+        canonTypeArgsVec.push_back(getCanonicalType(typeArg));
+      canonTypeArgs = canonTypeArgsVec;
     } else {
-      Canonical = getObjCObjectType(getCanonicalType(BaseType),
-                                    Protocols, NumProtocols);
+      canonTypeArgs = effectiveTypeArgs;
     }
 
+    ArrayRef<ObjCProtocolDecl *> canonProtocols;
+    SmallVector<ObjCProtocolDecl*, 8> canonProtocolsVec;
+    if (!protocolsSorted) {
+      canonProtocolsVec.insert(canonProtocolsVec.begin(),
+                               protocols.begin(), 
+                               protocols.end());
+      unsigned uniqueCount = protocols.size();
+      SortAndUniqueProtocols(&canonProtocolsVec[0], uniqueCount);
+      canonProtocols = llvm::makeArrayRef(&canonProtocolsVec[0], uniqueCount);
+    } else {
+      canonProtocols = protocols;
+    }
+
+    canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs,
+                                  canonProtocols);
+
     // Regenerate InsertPos.
     ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos);
   }
 
-  unsigned Size = sizeof(ObjCObjectTypeImpl);
-  Size += NumProtocols * sizeof(ObjCProtocolDecl *);
-  void *Mem = Allocate(Size, TypeAlignment);
+  unsigned size = sizeof(ObjCObjectTypeImpl);
+  size += typeArgs.size() * sizeof(QualType);
+  size += protocols.size() * sizeof(ObjCProtocolDecl *);
+  void *mem = Allocate(size, TypeAlignment);
   ObjCObjectTypeImpl *T =
-    new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols);
+    new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols);
 
   Types.push_back(T);
   ObjCObjectTypes.InsertNode(T, InsertPos);
@@ -5921,7 +5961,7 @@ void ASTContext::getObjCEncodingForTypeQ
 
 TypedefDecl *ASTContext::getObjCIdDecl() const {
   if (!ObjCIdDecl) {
-    QualType T = getObjCObjectType(ObjCBuiltinIdTy, nullptr, 0);
+    QualType T = getObjCObjectType(ObjCBuiltinIdTy, { }, { });
     T = getObjCObjectPointerType(T);
     ObjCIdDecl = buildImplicitTypedef(T, "id");
   }
@@ -5938,7 +5978,7 @@ TypedefDecl *ASTContext::getObjCSelDecl(
 
 TypedefDecl *ASTContext::getObjCClassDecl() const {
   if (!ObjCClassDecl) {
-    QualType T = getObjCObjectType(ObjCBuiltinClassTy, nullptr, 0);
+    QualType T = getObjCObjectType(ObjCBuiltinClassTy, { }, { });
     T = getObjCObjectPointerType(T);
     ObjCClassDecl = buildImplicitTypedef(T, "Class");
   }

Modified: cfe/trunk/lib/AST/ASTDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDiagnostic.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTDiagnostic.cpp (original)
+++ cfe/trunk/lib/AST/ASTDiagnostic.cpp Mon Jul  6 22:57:35 2015
@@ -125,12 +125,22 @@ break; \
   if (const PointerType *Ty = QT->getAs<PointerType>()) {
     QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
                                         ShouldAKA));
+  } else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) {
+    QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(),
+                                                  ShouldAKA));
   } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
     QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
                                                 ShouldAKA));
   } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) {
     QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(),
                                                 ShouldAKA));
+  } else if (const auto *Ty = QT->getAs<ObjCObjectType>()) {
+    if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) {
+      QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA);
+      QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(),
+                                     llvm::makeArrayRef(Ty->qual_begin(),
+                                                        Ty->getNumProtocols()));
+    }
   }
 
   return QC.apply(Context, QT);

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Jul  6 22:57:35 2015
@@ -1844,6 +1844,16 @@ QualType ASTNodeImporter::VisitObjCObjec
   if (ToBaseType.isNull())
     return QualType();
 
+  SmallVector<QualType, 4> TypeArgs;
+  for (auto TypeArg : T->getTypeArgs()) {
+    QualType ImportedTypeArg = Importer.Import(TypeArg);
+    if (ImportedTypeArg.isNull())
+      return QualType();
+
+    TypeArgs.push_back(ImportedTypeArg);
+  }
+
+
   SmallVector<ObjCProtocolDecl *, 4> Protocols;
   for (auto *P : T->quals()) {
     ObjCProtocolDecl *Protocol
@@ -1853,9 +1863,8 @@ QualType ASTNodeImporter::VisitObjCObjec
     Protocols.push_back(Protocol);
   }
 
-  return Importer.getToContext().getObjCObjectType(ToBaseType,
-                                                   Protocols.data(),
-                                                   Protocols.size());
+  return Importer.getToContext().getObjCObjectType(ToBaseType, TypeArgs,
+                                                   Protocols);
 }
 
 QualType
@@ -3694,13 +3703,11 @@ bool ASTNodeImporter::ImportDefinition(O
   
   // If this class has a superclass, import it.
   if (From->getSuperClass()) {
-    ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>(
-                                 Importer.Import(From->getSuperClass()));
-    if (!Super)
+    TypeSourceInfo *SuperTInfo = Importer.Import(From->getSuperClassTInfo());
+    if (!SuperTInfo)
       return true;
-    
-    To->setSuperClass(Super);
-    To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc()));
+
+    To->setSuperClass(SuperTInfo);
   }
   
   // Import protocols
@@ -5367,7 +5374,7 @@ TypeSourceInfo *ASTImporter::Import(Type
     return nullptr;
 
   return ToContext.getTrivialTypeSourceInfo(T, 
-                        FromTSI->getTypeLoc().getLocStart());
+           Import(FromTSI->getTypeLoc().getLocStart()));
 }
 
 Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) {

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Mon Jul  6 22:57:35 2015
@@ -259,6 +259,33 @@ ObjCTypeParamList *ObjCInterfaceDecl::ge
   return nullptr;
 }
 
+ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const {
+  // FIXME: Should make sure no callers ever do this.
+  if (!hasDefinition())
+    return nullptr;
+    
+  if (data().ExternallyCompleted)
+    LoadExternalDefinition();
+
+  if (const ObjCObjectType *superType = getSuperClassType()) {
+    if (ObjCInterfaceDecl *superDecl = superType->getInterface()) {
+      if (ObjCInterfaceDecl *superDef = superDecl->getDefinition())
+        return superDef;
+
+      return superDecl;
+    }
+  }
+
+  return nullptr;
+}
+
+SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const {
+  if (TypeSourceInfo *superTInfo = getSuperClassTInfo())
+    return superTInfo->getTypeLoc().getLocStart();
+  
+  return SourceLocation();
+}
+
 /// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
 /// with name 'PropertyId' in the primary class; including those in protocols
 /// (direct or indirect) used by the primary class.

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Jul  6 22:57:35 2015
@@ -467,19 +467,56 @@ const RecordType *Type::getAsUnionType()
 }
 
 ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
-                               ObjCProtocolDecl * const *Protocols,
-                               unsigned NumProtocols)
+                               ArrayRef<QualType> typeArgs,
+                               ArrayRef<ObjCProtocolDecl *> protocols)
   : Type(ObjCObject, Canonical, false, false, false, false),
     BaseType(Base) 
 {
-  ObjCObjectTypeBits.NumProtocols = NumProtocols;
-  assert(getNumProtocols() == NumProtocols &&
+  ObjCObjectTypeBits.NumTypeArgs = typeArgs.size();
+  assert(getTypeArgsAsWritten().size() == typeArgs.size() &&
+         "bitfield overflow in type argument count");
+  ObjCObjectTypeBits.NumProtocols = protocols.size();
+  assert(getNumProtocols() == protocols.size() &&
          "bitfield overflow in protocol count");
-  if (NumProtocols)
-    memcpy(getProtocolStorage(), Protocols,
-           NumProtocols * sizeof(ObjCProtocolDecl*));
+  if (!typeArgs.empty())
+    memcpy(getTypeArgStorage(), typeArgs.data(),
+           typeArgs.size() * sizeof(QualType));
+  if (!protocols.empty())
+    memcpy(getProtocolStorage(), protocols.data(),
+           protocols.size() * sizeof(ObjCProtocolDecl*));
 }
 
+bool ObjCObjectType::isSpecialized() const { 
+  // If we have type arguments written here, the type is specialized.
+  if (ObjCObjectTypeBits.NumTypeArgs > 0)
+    return true;
+
+  if (!qual_empty()) {
+    // Otherwise, check whether the base type is specialized.
+    if (auto objcObject = getBaseType()->getAs<ObjCObjectType>())
+      return objcObject->isSpecialized();
+  }
+
+  // Not specialized.
+  return false;
+}
+
+ArrayRef<QualType> ObjCObjectType::getTypeArgs() const {
+  // We have type arguments written on this type.
+  if (isSpecializedAsWritten())
+    return getTypeArgsAsWritten();
+
+  if (!qual_empty()) {
+    // Look at the base type, which might have type arguments.
+    if (auto objcObject = getBaseType()->getAs<ObjCObjectType>())
+      return objcObject->getTypeArgs();
+  }
+
+  // No type arguments.
+  return { };
+}
+
+
 const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const {
   // There is no sugar for ObjCObjectType's, just return the canonical
   // type pointer if it is the right class.  There is no typedef information to
@@ -2076,15 +2113,20 @@ QualifierCollector::apply(const ASTConte
 
 void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID,
                                  QualType BaseType,
-                                 ObjCProtocolDecl * const *Protocols,
-                                 unsigned NumProtocols) {
+                                 ArrayRef<QualType> typeArgs,
+                                 ArrayRef<ObjCProtocolDecl *> protocols) {
   ID.AddPointer(BaseType.getAsOpaquePtr());
-  for (unsigned i = 0; i != NumProtocols; i++)
-    ID.AddPointer(Protocols[i]);
+  ID.AddInteger(typeArgs.size());
+  for (auto typeArg : typeArgs)
+    ID.AddPointer(typeArg.getAsOpaquePtr());
+  ID.AddInteger(protocols.size());
+  for (auto proto : protocols)
+    ID.AddPointer(proto);
 }
 
 void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getBaseType(), qual_begin(), getNumProtocols());
+  Profile(ID, getBaseType(), getTypeArgs(), 
+          llvm::makeArrayRef(qual_begin(), getNumProtocols()));
 }
 
 namespace {
@@ -2495,6 +2537,39 @@ Optional<NullabilityKind> AttributedType
   return None;
 }
 
+bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const {
+  const ObjCObjectPointerType *objcPtr = getAs<ObjCObjectPointerType>();
+  if (!objcPtr)
+    return false;
+
+  if (objcPtr->isObjCIdType()) {
+    // id is always okay.
+    return true;
+  }
+
+  // Blocks are NSObjects.
+  if (ObjCInterfaceDecl *iface = objcPtr->getInterfaceDecl()) {
+    if (iface->getIdentifier() != ctx.getNSObjectName())
+      return false;
+
+    // Continue to check qualifiers, below.
+  } else if (objcPtr->isObjCQualifiedIdType()) {
+    // Continue to check qualifiers, below.
+  } else {
+    return false;
+  }
+
+  // Check protocol qualifiers.
+  for (ObjCProtocolDecl *proto : objcPtr->quals()) {
+    // Blocks conform to NSObject and NSCopying.
+    if (proto->getIdentifier() != ctx.getNSObjectName() &&
+        proto->getIdentifier() != ctx.getNSCopyingName())
+      return false;
+  }
+
+  return true;
+}
+
 Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const {
   if (isObjCARCImplicitlyUnretainedType())
     return Qualifiers::OCL_ExplicitNone;

Modified: cfe/trunk/lib/AST/TypeLoc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeLoc.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypeLoc.cpp (original)
+++ cfe/trunk/lib/AST/TypeLoc.cpp Mon Jul  6 22:57:35 2015
@@ -312,6 +312,22 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLo
   return TL;
 }
 
+void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, 
+                                        SourceLocation Loc) {
+  setHasBaseTypeAsWritten(true);
+  setTypeArgsLAngleLoc(Loc);
+  setTypeArgsRAngleLoc(Loc);
+  for (unsigned i = 0, e = getNumTypeArgs(); i != e; ++i) {
+    setTypeArgTInfo(i, 
+                   Context.getTrivialTypeSourceInfo(
+                     getTypePtr()->getTypeArgsAsWritten()[i], Loc));
+  }
+  setProtocolLAngleLoc(Loc);
+  setProtocolRAngleLoc(Loc);
+  for (unsigned i = 0, e = getNumProtocols(); i != e; ++i)
+    setProtocolLoc(i, Loc);
+}
+
 void TypeOfTypeLoc::initializeLocal(ASTContext &Context,
                                        SourceLocation Loc) {
   TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo>

Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Mon Jul  6 22:57:35 2015
@@ -1310,59 +1310,56 @@ void TypePrinter::printObjCInterfaceAfte
 
 void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T,
                                         raw_ostream &OS) {
-  if (T->qual_empty())
+  if (T->qual_empty() && T->isUnspecializedAsWritten())
     return printBefore(T->getBaseType(), OS);
 
   print(T->getBaseType(), OS, StringRef());
-  OS << '<';
-  bool isFirst = true;
-  for (const auto *I : T->quals()) {
-    if (isFirst)
-      isFirst = false;
-    else
-      OS << ',';
-    OS << I->getName();
+
+  if (T->isSpecializedAsWritten()) {
+    bool isFirst = true;
+    OS << '<';
+    for (auto typeArg : T->getTypeArgsAsWritten()) {
+      if (isFirst)
+        isFirst = false;
+      else
+        OS << ",";
+
+      print(typeArg, OS, StringRef());
+    }
+    OS << '>';
+  }
+
+  if (!T->qual_empty()) {
+    bool isFirst = true;
+    OS << '<';
+    for (const auto *I : T->quals()) {
+      if (isFirst)
+        isFirst = false;
+      else
+        OS << ',';
+      OS << I->getName();
+    }
+    OS << '>';
   }
-  OS << '>';
+
   spaceBeforePlaceHolder(OS);
 }
 void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T,
                                         raw_ostream &OS) {
-  if (T->qual_empty())
+  if (T->qual_empty() && T->isUnspecializedAsWritten())
     return printAfter(T->getBaseType(), OS);
 }
 
 void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T, 
                                                raw_ostream &OS) {
-  T->getPointeeType().getLocalQualifiers().print(OS, Policy,
-                                                /*appendSpaceIfNonEmpty=*/true);
+  printBefore(T->getPointeeType(), OS);
 
-  assert(!T->isObjCSelType());
-
-  if (T->isObjCIdType() || T->isObjCQualifiedIdType())
-    OS << "id";
-  else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
-    OS << "Class";
-  else
-    OS << T->getInterfaceDecl()->getName();
-  
-  if (!T->qual_empty()) {
-    OS << '<';
-    for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), 
-                                              E = T->qual_end();
-         I != E; ++I) {
-      OS << (*I)->getName();
-      if (I+1 != E)
-        OS << ',';
-    }
-    OS << '>';
-  }
-  
+  // If we need to print the pointer, print it now.
   if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() &&
       !T->isObjCClassType() && !T->isObjCQualifiedClassType()) {
-    OS << " *"; // Don't forget the implicit pointer.
-  } else {
-    spaceBeforePlaceHolder(OS);
+    if (HasEmptyPlaceHolder)
+      OS << ' ';
+    OS << '*';
   }
 }
 void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, 

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul  6 22:57:35 2015
@@ -2886,11 +2886,26 @@ void Parser::ParseDeclarationSpecifiers(
       DS.SetRangeEnd(Tok.getAnnotationEndLoc());
       ConsumeToken(); // The typename
 
-      // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
-      // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
-      // Objective-C interface.
-      if (Tok.is(tok::less) && getLangOpts().ObjC1)
-        ParseObjCProtocolQualifiers(DS);
+      // Objective-C supports type arguments and protocol references
+      // following an Objective-C object pointer type. Handle either
+      // one of them.
+      if (Tok.is(tok::less) && getLangOpts().ObjC1) {
+        ParseObjCTypeArgsOrProtocolQualifiers(
+          DS, /*warnOnIncompleteProtocols=*/false);
+
+        // An Objective-C object pointer followed by type arguments
+        // can then be followed again by a set of protocol references, e.g.,
+        // \c NSArray<NSView><NSTextDelegate>
+        if (Tok.is(tok::less)) {
+          if (DS.getProtocolQualifiers()) {
+            Diag(Tok, diag::err_objc_type_args_after_protocols)
+              << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
+            SkipUntil(tok::greater, tok::greatergreater);
+          } else {
+            ParseObjCProtocolQualifiers(DS);
+          }
+        }
+      }
 
       continue;
     }
@@ -2997,11 +3012,26 @@ void Parser::ParseDeclarationSpecifiers(
       DS.SetRangeEnd(Tok.getLocation());
       ConsumeToken(); // The identifier
 
-      // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
-      // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
-      // Objective-C interface.
-      if (Tok.is(tok::less) && getLangOpts().ObjC1)
-        ParseObjCProtocolQualifiers(DS);
+      // Objective-C supports type arguments and protocol references
+      // following an Objective-C object pointer type. Handle either
+      // one of them.
+      if (Tok.is(tok::less) && getLangOpts().ObjC1) {
+        ParseObjCTypeArgsOrProtocolQualifiers(
+          DS, /*warnOnIncompleteProtocols=*/false);
+
+        // An Objective-C object pointer followed by type arguments
+        // can then be followed again by a set of protocol references, e.g.,
+        // \c NSArray<NSView><NSTextDelegate>
+        if (Tok.is(tok::less)) {
+          if (DS.getProtocolQualifiers()) {
+            Diag(Tok, diag::err_objc_type_args_after_protocols)
+              << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
+            SkipUntil(tok::greater, tok::greatergreater);
+          } else {
+            ParseObjCProtocolQualifiers(DS);
+          }
+        }
+      }
 
       // Need to support trailing type qualifiers (e.g. "id<p> const").
       // If a type specifier follows, it will be diagnosed elsewhere.

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Mon Jul  6 22:57:35 2015
@@ -179,7 +179,7 @@ void Parser::CheckNestedObjCContexts(Sou
 ///     @end
 ///
 ///   objc-superclass:
-///     ':' identifier
+///     ':' identifier objc-type-arguments[opt]
 ///
 ///   objc-class-interface-attributes:
 ///     __attribute__((visibility("default")))
@@ -293,6 +293,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
   // Parse a class interface.
   IdentifierInfo *superClassId = nullptr;
   SourceLocation superClassLoc;
+  DeclSpec superClassDS(AttrFactory);
 
   if (Tok.is(tok::colon)) { // a super class is specified.
     ConsumeToken();
@@ -311,18 +312,12 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
     }
     superClassId = Tok.getIdentifierInfo();
     superClassLoc = ConsumeToken();
-  } else if (typeParameterList) {
-    // An objc-type-parameter-list is ambiguous with an objc-protocol-refs
-    // in an @interface without a specified superclass, so such classes
-    // are ill-formed. We have determined that we have an
-    // objc-type-parameter-list but no superclass, so complain and record
-    // as if we inherited from NSObject.
-    SourceLocation insertLoc = PP.getLocForEndOfToken(PrevTokLocation);
-    Diag(insertLoc, diag::err_objc_parameterized_class_without_base)
-      << nameId
-      << FixItHint::CreateInsertion(insertLoc, " : NSObject");
-    superClassId = PP.getIdentifierInfo("NSObject");
-    superClassLoc = Tok.getLocation();
+
+    // Type arguments for the superclass or protocol conformances.
+    if (Tok.is(tok::less)) {
+      ParseObjCTypeArgsOrProtocolQualifiers(superClassDS,
+                                            /*warnOnIncompleteProtocols=*/true);
+    }
   }
   
   // Next, we need to check for any protocol references.
@@ -338,6 +333,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
                                     /*ForObjCContainer=*/true,
                                     &ProtocolIdents[0], ProtocolIdents.size(),
                                     ProtocolRefs);
+  } else if (auto protocols = superClassDS.getProtocolQualifiers()) {
+    // We already parsed the protocols named when we thought we had a
+    // type argument list (for a specialized superclass). Treat them
+    // as actual protocol references.
+    unsigned numProtocols = superClassDS.getNumProtocolQualifiers();
+    ProtocolRefs.append(protocols, protocols + numProtocols);
+    ProtocolLocs.append(superClassDS.getProtocolLocs(),
+                        superClassDS.getProtocolLocs() + numProtocols);
+    LAngleLoc = superClassDS.getProtocolLAngleLoc();
+    EndProtoLoc = superClassDS.getLocEnd();
   } else if (Tok.is(tok::less) &&
              ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
                                          LAngleLoc, EndProtoLoc)) {
@@ -348,8 +353,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
     Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
   
   Decl *ClsType =
-    Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList,
-                                     superClassId, superClassLoc,
+    Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, 
+                                     typeParameterList, superClassId, 
+                                     superClassLoc, 
+                                     superClassDS.getObjCTypeArgs(),
+                                     superClassDS.getObjCTypeArgsRange(),
                                      ProtocolRefs.data(), ProtocolRefs.size(),
                                      ProtocolLocs.data(),
                                      EndProtoLoc, attrs.getList());
@@ -1554,8 +1562,7 @@ bool Parser::ParseObjCProtocolQualifiers
   SmallVector<Decl *, 8> ProtocolDecl;
   SmallVector<SourceLocation, 8> ProtocolLocs;
   bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
-                                            false,
-                                            LAngleLoc, EndProtoLoc);
+                                            false, LAngleLoc, EndProtoLoc);
   DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
                            ProtocolLocs.data(), LAngleLoc);
   if (EndProtoLoc.isValid())
@@ -1563,6 +1570,111 @@ bool Parser::ParseObjCProtocolQualifiers
   return Result;
 }
 
+/// Parse Objective-C type arguments or protocol qualifiers.
+///
+///   objc-type-arguments:
+///     '<' type-name (',' type-name)* '>'
+///
+void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
+       DeclSpec &DS,
+       bool warnOnIncompleteProtocols) {
+  assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
+  SourceLocation lAngleLoc = ConsumeToken();
+
+  // Whether all of the elements we've parsed thus far are single
+  // identifiers, which might be types or might be protocols.
+  bool allSingleIdentifiers = true;
+  SmallVector<IdentifierInfo *, 4> identifiers;
+  SmallVector<SourceLocation, 4> identifierLocs;
+
+  // Parse a list of comma-separated identifiers, bailing out if we
+  // see something different.
+  do {
+    // Parse a single identifier.
+    if (Tok.is(tok::identifier) &&
+        (NextToken().is(tok::comma) ||
+         NextToken().is(tok::greater) ||
+         NextToken().is(tok::greatergreater))) {
+      identifiers.push_back(Tok.getIdentifierInfo());
+      identifierLocs.push_back(ConsumeToken());
+      continue;
+    }
+
+    if (Tok.is(tok::code_completion)) {
+      // FIXME: Also include types here.
+      SmallVector<IdentifierLocPair, 4> identifierLocPairs;
+      for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+        identifierLocPairs.push_back(IdentifierLocPair(identifiers[i], 
+                                                       identifierLocs[i]));
+      }
+
+      Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(),
+                                                 identifierLocPairs.size());
+      cutOffParsing();
+      return;
+    }
+
+    allSingleIdentifiers = false;
+    break;
+  } while (TryConsumeToken(tok::comma));
+
+  // If we parsed an identifier list, semantic analysis sorts out
+  // whether it refers to protocols or to type arguments.
+  if (allSingleIdentifiers) {
+    // Parse the closing '>'.
+    SourceLocation rAngleLoc;
+    (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+                                         /*ObjCGenericList=*/true);
+
+    // Let Sema figure out what we parsed.
+    Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
+                                                  DS,
+                                                  lAngleLoc,
+                                                  identifiers,
+                                                  identifierLocs,
+                                                  rAngleLoc,
+                                                  warnOnIncompleteProtocols);
+    return;
+  }
+
+  // We syntactically matched a type argument, so commit to parsing
+  // type arguments.
+  SmallVector<ParsedType, 4> typeArgs;
+
+  // Convert the identifiers into type arguments.
+  bool invalid = false;
+  for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+    ParsedType typeArg
+      = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
+    if (typeArg) {
+      typeArgs.push_back(typeArg);
+    } else {
+      invalid = true;
+    }
+  }
+
+  // Continue parsing type-names.
+  do {
+    TypeResult typeArg = ParseTypeName();
+    if (typeArg.isUsable()) {
+      typeArgs.push_back(typeArg.get());
+    } else {
+      invalid = true;
+    }
+  } while (TryConsumeToken(tok::comma));
+
+  // Parse the closing '>'.
+  SourceLocation rAngleLoc;
+  (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+                                       /*ObjCGenericList=*/true);
+
+  if (invalid)
+    return;
+
+  // Update the DeclSpec appropriately.
+  DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+}
+
 void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
                                  BalancedDelimiterTracker &T,
                                  SmallVectorImpl<Decl *> &AllIvarDecls,

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Mon Jul  6 22:57:35 2015
@@ -1384,7 +1384,7 @@ Parser::isCXXDeclarationSpecifier(Parser
   case_typename:
     // In Objective-C, we might have a protocol-qualified type.
     if (getLangOpts().ObjC1 && NextToken().is(tok::less)) {
-      // Tentatively parse the 
+      // Tentatively parse the protocol qualifiers.
       TentativeParsingAction PA(*this);
       ConsumeToken(); // The type token
       

Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Sema/DeclSpec.cpp Mon Jul  6 22:57:35 2015
@@ -893,6 +893,7 @@ bool DeclSpec::SetConstexprSpec(SourceLo
   return false;
 }
 
+
 bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec,
                               unsigned &DiagID) {
   if (Concept_specified) {
@@ -905,6 +906,16 @@ bool DeclSpec::SetConceptSpec(SourceLoca
   return false;
 }
 
+void DeclSpec::setObjCTypeArgs(SourceLocation lAngleLoc,
+                               ArrayRef<ParsedType> args,
+                               SourceLocation rAngleLoc) {
+  ParsedType *argsCopy = new ParsedType[args.size()];
+  memcpy(argsCopy, args.data(), args.size() * sizeof(ParsedType));
+  ObjCTypeArgs = llvm::makeArrayRef(argsCopy, args.size());
+  ObjCTypeArgsLAngleLoc = lAngleLoc;
+  ObjCTypeArgsRAngleLoc = rAngleLoc;
+}
+
 void DeclSpec::setProtocolQualifiers(Decl * const *Protos,
                                      unsigned NP,
                                      SourceLocation *ProtoLocs,

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Jul  6 22:57:35 2015
@@ -464,6 +464,142 @@ static void diagnoseUseOfProtocols(Sema
   }
 }
 
+void Sema::
+ActOnSuperClassOfClassInterface(Scope *S,
+                                SourceLocation AtInterfaceLoc,
+                                ObjCInterfaceDecl *IDecl,
+                                IdentifierInfo *ClassName,
+                                SourceLocation ClassLoc,
+                                IdentifierInfo *SuperName,
+                                SourceLocation SuperLoc,
+                                ArrayRef<ParsedType> SuperTypeArgs,
+                                SourceRange SuperTypeArgsRange) {
+  // Check if a different kind of symbol declared in this scope.
+  NamedDecl *PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc,
+                                         LookupOrdinaryName);
+
+  if (!PrevDecl) {
+    // Try to correct for a typo in the superclass name without correcting
+    // to the class we're defining.
+    if (TypoCorrection Corrected = CorrectTypo(
+            DeclarationNameInfo(SuperName, SuperLoc),
+            LookupOrdinaryName, TUScope,
+            NULL, llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl),
+            CTK_ErrorRecovery)) {
+      diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
+                   << SuperName << ClassName);
+      PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
+    }
+  }
+
+  if (declaresSameEntity(PrevDecl, IDecl)) {
+    Diag(SuperLoc, diag::err_recursive_superclass)
+      << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
+    IDecl->setEndOfDefinitionLoc(ClassLoc);
+  } else {
+    ObjCInterfaceDecl *SuperClassDecl =
+    dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+    QualType SuperClassType;
+
+    // Diagnose classes that inherit from deprecated classes.
+    if (SuperClassDecl) {
+      (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc);
+      SuperClassType = Context.getObjCInterfaceType(SuperClassDecl);
+    }
+
+    if (PrevDecl && SuperClassDecl == 0) {
+      // The previous declaration was not a class decl. Check if we have a
+      // typedef. If we do, get the underlying class type.
+      if (const TypedefNameDecl *TDecl =
+          dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
+        QualType T = TDecl->getUnderlyingType();
+        if (T->isObjCObjectType()) {
+          if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
+            SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
+            SuperClassType = Context.getTypeDeclType(TDecl);
+
+            // This handles the following case:
+            // @interface NewI @end
+            // typedef NewI DeprI __attribute__((deprecated("blah")))
+            // @interface SI : DeprI /* warn here */ @end
+            (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc);
+          }
+        }
+      }
+
+      // This handles the following case:
+      //
+      // typedef int SuperClass;
+      // @interface MyClass : SuperClass {} @end
+      //
+      if (!SuperClassDecl) {
+        Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName;
+        Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+      }
+    }
+
+    if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
+      if (!SuperClassDecl)
+        Diag(SuperLoc, diag::err_undef_superclass)
+          << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
+      else if (RequireCompleteType(SuperLoc,
+                                   SuperClassType,
+                                   diag::err_forward_superclass,
+                                   SuperClassDecl->getDeclName(),
+                                   ClassName,
+                                   SourceRange(AtInterfaceLoc, ClassLoc))) {
+        SuperClassDecl = 0;
+        SuperClassType = QualType();
+      }
+    }
+
+    if (SuperClassType.isNull()) {
+      assert(!SuperClassDecl && "Failed to set SuperClassType?");
+      return;
+    }
+
+    // Handle type arguments on the superclass.
+    TypeSourceInfo *SuperClassTInfo = nullptr;
+    if (!SuperTypeArgs.empty()) {
+      // Form declaration specifiers naming this superclass type with
+      // type arguments.
+      AttributeFactory attrFactory;
+      DeclSpec DS(attrFactory);
+      const char* prevSpec; // unused
+      unsigned diagID; // unused
+      TypeSourceInfo *parsedTSInfo
+        = Context.getTrivialTypeSourceInfo(SuperClassType, SuperLoc);
+      ParsedType parsedType = CreateParsedType(SuperClassType, parsedTSInfo);
+
+      DS.SetTypeSpecType(DeclSpec::TST_typename, SuperLoc, prevSpec, diagID,
+                         parsedType, Context.getPrintingPolicy());
+      DS.SetRangeStart(SuperLoc);
+      DS.SetRangeEnd(SuperLoc);
+      DS.setObjCTypeArgs(SuperTypeArgsRange.getBegin(),
+                         SuperTypeArgs,
+                         SuperTypeArgsRange.getEnd());
+
+      // Form the declarator.
+      Declarator D(DS, Declarator::TypeNameContext);
+     
+      TypeResult fullSuperClassType = ActOnTypeName(S, D);
+      if (!fullSuperClassType.isUsable())
+        return;
+
+      SuperClassType = GetTypeFromParser(fullSuperClassType.get(), 
+                                         &SuperClassTInfo);
+    }
+
+    if (!SuperClassTInfo) {
+      SuperClassTInfo = Context.getTrivialTypeSourceInfo(SuperClassType, 
+                                                         SuperLoc);
+    }
+
+    IDecl->setSuperClass(SuperClassTInfo);
+    IDecl->setEndOfDefinitionLoc(SuperClassTInfo->getTypeLoc().getLocEnd());
+  }
+}
+
 DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
                                     SourceLocation paramLoc,
                                     SourceLocation colonLoc,
@@ -499,7 +635,7 @@ DeclResult Sema::actOnObjCTypeParam(Scop
       // Form the new type source information.
       typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound);
     } else {
-      // Not a
+      // Not a valid type bound.
       Diag(typeBoundInfo->getTypeLoc().getBeginLoc(),
            diag::err_objc_type_param_bound_nonobject)
         << typeBound << paramName;
@@ -669,10 +805,12 @@ static bool checkTypeParamListConsistenc
 }
 
 Decl *Sema::
-ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc,
                          IdentifierInfo *ClassName, SourceLocation ClassLoc,
                          ObjCTypeParamList *typeParamList,
                          IdentifierInfo *SuperName, SourceLocation SuperLoc,
+                         ArrayRef<ParsedType> SuperTypeArgs,
+                         SourceRange SuperTypeArgsRange,
                          Decl * const *ProtoRefs, unsigned NumProtoRefs,
                          const SourceLocation *ProtoLocs, 
                          SourceLocation EndProtoLoc, AttributeList *AttrList) {
@@ -767,84 +905,13 @@ ActOnStartClassInterface(SourceLocation
     IDecl->startDefinition();
   
   if (SuperName) {
-    // Check if a different kind of symbol declared in this scope.
-    PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc,
-                                LookupOrdinaryName);
-
-    if (!PrevDecl) {
-      // Try to correct for a typo in the superclass name without correcting
-      // to the class we're defining.
-      if (TypoCorrection Corrected =
-              CorrectTypo(DeclarationNameInfo(SuperName, SuperLoc),
-                          LookupOrdinaryName, TUScope, nullptr,
-                          llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl),
-                          CTK_ErrorRecovery)) {
-        diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
-                                    << SuperName << ClassName);
-        PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
-      }
-    }
-
-    if (declaresSameEntity(PrevDecl, IDecl)) {
-      Diag(SuperLoc, diag::err_recursive_superclass)
-        << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
-      IDecl->setEndOfDefinitionLoc(ClassLoc);
-    } else {
-      ObjCInterfaceDecl *SuperClassDecl =
-                                dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
-
-      // Diagnose availability in the context of the @interface.
-      ContextRAII SavedContext(*this, IDecl);
-      // Diagnose classes that inherit from deprecated classes.
-      if (SuperClassDecl)
-        (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc);
-
-      if (PrevDecl && !SuperClassDecl) {
-        // The previous declaration was not a class decl. Check if we have a
-        // typedef. If we do, get the underlying class type.
-        if (const TypedefNameDecl *TDecl =
-              dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
-          QualType T = TDecl->getUnderlyingType();
-          if (T->isObjCObjectType()) {
-            if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
-              SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
-              // This handles the following case:
-              // @interface NewI @end
-              // typedef NewI DeprI __attribute__((deprecated("blah")))
-              // @interface SI : DeprI /* warn here */ @end
-              (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc);
-            }
-          }
-        }
-
-        // This handles the following case:
-        //
-        // typedef int SuperClass;
-        // @interface MyClass : SuperClass {} @end
-        //
-        if (!SuperClassDecl) {
-          Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName;
-          Diag(PrevDecl->getLocation(), diag::note_previous_definition);
-        }
-      }
+    // Diagnose availability in the context of the @interface.
+    ContextRAII SavedContext(*this, IDecl);
 
-      if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
-        if (!SuperClassDecl)
-          Diag(SuperLoc, diag::err_undef_superclass)
-            << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
-        else if (RequireCompleteType(SuperLoc, 
-                                  Context.getObjCInterfaceType(SuperClassDecl),
-                                     diag::err_forward_superclass,
-                                     SuperClassDecl->getDeclName(),
-                                     ClassName,
-                                     SourceRange(AtInterfaceLoc, ClassLoc))) {
-          SuperClassDecl = nullptr;
-        }
-      }
-      IDecl->setSuperClass(SuperClassDecl);
-      IDecl->setSuperClassLoc(SuperLoc);
-      IDecl->setEndOfDefinitionLoc(SuperLoc);
-    }
+    ActOnSuperClassOfClassInterface(S, AtInterfaceLoc, IDecl, 
+                                    ClassName, ClassLoc, 
+                                    SuperName, SuperLoc, SuperTypeArgs, 
+                                    SuperTypeArgsRange);
   } else { // we have a root class.
     IDecl->setEndOfDefinitionLoc(ClassLoc);
   }
@@ -1091,6 +1158,325 @@ Sema::FindProtocolDeclaration(bool WarnO
   }
 }
 
+// Callback to only accept typo corrections that are either
+// Objective-C protocols or valid Objective-C type arguments.
+class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback {
+  ASTContext &Context;
+  Sema::LookupNameKind LookupKind;
+ public:
+  ObjCTypeArgOrProtocolValidatorCCC(ASTContext &context,
+                                    Sema::LookupNameKind lookupKind)
+    : Context(context), LookupKind(lookupKind) { }
+
+  bool ValidateCandidate(const TypoCorrection &candidate) override {
+    // If we're allowed to find protocols and we have a protocol, accept it.
+    if (LookupKind != Sema::LookupOrdinaryName) {
+      if (candidate.getCorrectionDeclAs<ObjCProtocolDecl>())
+        return true;
+    }
+
+    // If we're allowed to find type names and we have one, accept it.
+    if (LookupKind != Sema::LookupObjCProtocolName) {
+      // If we have a type declaration, we might accept this result.
+      if (auto typeDecl = candidate.getCorrectionDeclAs<TypeDecl>()) {
+        // If we found a tag declaration outside of C++, skip it. This
+        // can happy because we look for any name when there is no
+        // bias to protocol or type names.
+        if (isa<RecordDecl>(typeDecl) && !Context.getLangOpts().CPlusPlus)
+          return false;
+
+        // Make sure the type is something we would accept as a type
+        // argument.
+        auto type = Context.getTypeDeclType(typeDecl);
+        if (type->isObjCObjectPointerType() ||
+            type->isBlockPointerType() ||
+            type->isDependentType() ||
+            type->isObjCObjectType())
+          return true;
+
+        return false;
+      }
+
+      // If we have an Objective-C class type, accept it; there will
+      // be another fix to add the '*'.
+      if (candidate.getCorrectionDeclAs<ObjCInterfaceDecl>())
+        return true;
+
+      return false;
+    }
+
+    return false;
+  }
+};
+
+void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
+       Scope *S,
+       DeclSpec &DS,
+       SourceLocation lAngleLoc,
+       ArrayRef<IdentifierInfo *> identifiers,
+       ArrayRef<SourceLocation> identifierLocs,
+       SourceLocation rAngleLoc,
+       bool warnOnIncompleteProtocols) {
+  // Local function that updates the declaration specifiers with
+  // protocol information.
+  SmallVector<ObjCProtocolDecl *, 4> protocols;
+  unsigned numProtocolsResolved = 0;
+  auto resolvedAsProtocols = [&] {
+    assert(numProtocolsResolved == identifiers.size() && "Unresolved protocols");
+    
+    for (unsigned i = 0, n = protocols.size(); i != n; ++i) {
+      ObjCProtocolDecl *&proto = protocols[i];
+      // For an objc container, delay protocol reference checking until after we
+      // can set the objc decl as the availability context, otherwise check now.
+      if (!warnOnIncompleteProtocols) {
+        (void)DiagnoseUseOfDecl(proto, identifierLocs[i]);
+      }
+
+      // If this is a forward protocol declaration, get its definition.
+      if (!proto->isThisDeclarationADefinition() && proto->getDefinition())
+        proto = proto->getDefinition();
+
+      // If this is a forward declaration and we are supposed to warn in this
+      // case, do it.
+      // FIXME: Recover nicely in the hidden case.
+      ObjCProtocolDecl *forwardDecl = nullptr;
+      if (warnOnIncompleteProtocols &&
+          NestedProtocolHasNoDefinition(proto, forwardDecl)) {
+        Diag(identifierLocs[i], diag::warn_undef_protocolref)
+          << proto->getDeclName();
+        Diag(forwardDecl->getLocation(), diag::note_protocol_decl_undefined)
+          << forwardDecl;
+      }
+    }
+
+    DS.setProtocolQualifiers((Decl * const *)(protocols.data()),
+                             protocols.size(),
+                             const_cast<SourceLocation *>(identifierLocs.data()),
+                             lAngleLoc);
+    if (rAngleLoc.isValid())
+      DS.SetRangeEnd(rAngleLoc);
+  };
+
+  // Attempt to resolve all of the identifiers as protocols.
+  for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+    ObjCProtocolDecl *proto = LookupProtocol(identifiers[i], identifierLocs[i]);
+    protocols.push_back(proto);
+    if (proto)
+      ++numProtocolsResolved;
+  }
+
+  // If all of the names were protocols, these were protocol qualifiers.
+  if (numProtocolsResolved == identifiers.size())
+    return resolvedAsProtocols();
+
+  // Attempt to resolve all of the identifiers as type names or
+  // Objective-C class names. The latter is technically ill-formed,
+  // but is probably something like \c NSArray<NSView *> missing the
+  // \c*.
+  typedef llvm::PointerUnion<TypeDecl *, ObjCInterfaceDecl *> TypeOrClassDecl;
+  SmallVector<TypeOrClassDecl, 4> typeDecls;
+  unsigned numTypeDeclsResolved = 0;
+  for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+    NamedDecl *decl = LookupSingleName(S, identifiers[i], identifierLocs[i],
+                                       LookupOrdinaryName);
+    if (!decl) {
+      typeDecls.push_back(TypeOrClassDecl());
+      continue;
+    }
+
+    if (auto typeDecl = dyn_cast<TypeDecl>(decl)) {
+      typeDecls.push_back(typeDecl);
+      ++numTypeDeclsResolved;
+      continue;
+    }
+
+    if (auto objcClass = dyn_cast<ObjCInterfaceDecl>(decl)) {
+      typeDecls.push_back(objcClass);
+      ++numTypeDeclsResolved;
+      continue;
+    }
+
+    typeDecls.push_back(TypeOrClassDecl());
+  }
+
+  AttributeFactory attrFactory;
+
+  // Local function that forms a reference to the given type or
+  // Objective-C class declaration.
+  auto resolveTypeReference = [&](TypeOrClassDecl typeDecl, SourceLocation loc) 
+                                -> TypeResult {
+    // Form declaration specifiers. They simply refer to the type.
+    DeclSpec DS(attrFactory);
+    const char* prevSpec; // unused
+    unsigned diagID; // unused
+    QualType type;
+    if (auto *actualTypeDecl = typeDecl.dyn_cast<TypeDecl *>())
+      type = Context.getTypeDeclType(actualTypeDecl);
+    else
+      type = Context.getObjCInterfaceType(typeDecl.get<ObjCInterfaceDecl *>());
+    TypeSourceInfo *parsedTSInfo = Context.getTrivialTypeSourceInfo(type, loc);
+    ParsedType parsedType = CreateParsedType(type, parsedTSInfo);
+    DS.SetTypeSpecType(DeclSpec::TST_typename, loc, prevSpec, diagID,
+                       parsedType, Context.getPrintingPolicy());
+    // Use the identifier location for the type source range.
+    DS.SetRangeStart(loc);
+    DS.SetRangeEnd(loc);
+
+    // Form the declarator.
+    Declarator D(DS, Declarator::TypeNameContext);
+
+    // If we have a typedef of an Objective-C class type that is missing a '*',
+    // add the '*'.
+    if (type->getAs<ObjCInterfaceType>()) {
+      SourceLocation starLoc = PP.getLocForEndOfToken(loc);
+      ParsedAttributes parsedAttrs(attrFactory);
+      D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc,
+                                                SourceLocation(),
+                                                SourceLocation(),
+                                                SourceLocation(),
+                                                SourceLocation()),
+                    parsedAttrs,
+                    starLoc);
+
+      // Diagnose the missing '*'.
+      Diag(loc, diag::err_objc_type_arg_missing_star)
+        << type
+        << FixItHint::CreateInsertion(starLoc, " *");
+    }
+
+    // Convert this to a type.
+    return ActOnTypeName(S, D);
+  };
+
+  // Local function that updates the declaration specifiers with
+  // type argument information.
+  auto resolvedAsTypeDecls = [&] {
+    assert(numTypeDeclsResolved == identifiers.size() && "Unresolved type decl");
+    // Map type declarations to type arguments.
+    SmallVector<ParsedType, 4> typeArgs;
+    for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+      // Map type reference to a type.
+      TypeResult type = resolveTypeReference(typeDecls[i], identifierLocs[i]);
+      if (!type.isUsable())
+        return;
+
+      typeArgs.push_back(type.get());
+    }
+
+    // Record the Objective-C type arguments.
+    DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+  };
+
+  // If all of the identifiers can be resolved as type names or
+  // Objective-C class names, we have type arguments.
+  if (numTypeDeclsResolved == identifiers.size())
+    return resolvedAsTypeDecls();
+
+  // Error recovery: some names weren't found, or we have a mix of
+  // type and protocol names. Go resolve all of the unresolved names
+  // and complain if we can't find a consistent answer.
+  LookupNameKind lookupKind = LookupAnyName;
+  for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+    // If we already have a protocol or type. Check whether it is the
+    // right thing.
+    if (protocols[i] || typeDecls[i]) {
+      // If we haven't figured out whether we want types or protocols
+      // yet, try to figure it out from this name.
+      if (lookupKind == LookupAnyName) {
+        // If this name refers to both a protocol and a type (e.g., \c
+        // NSObject), don't conclude anything yet.
+        if (protocols[i] && typeDecls[i])
+          continue;
+
+        // Otherwise, let this name decide whether we'll be correcting
+        // toward types or protocols.
+        lookupKind = protocols[i] ? LookupObjCProtocolName
+                                  : LookupOrdinaryName;
+        continue;
+      }
+
+      // If we want protocols and we have a protocol, there's nothing
+      // more to do.
+      if (lookupKind == LookupObjCProtocolName && protocols[i])
+        continue;
+
+      // If we want types and we have a type declaration, there's
+      // nothing more to do.
+      if (lookupKind == LookupOrdinaryName && typeDecls[i])
+        continue;
+
+      // We have a conflict: some names refer to protocols and others
+      // refer to types.
+      Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols)
+        << (protocols[i] != nullptr)
+        << identifiers[i]
+        << identifiers[0]
+        << SourceRange(identifierLocs[0]);
+
+      return;
+    }
+
+    // Perform typo correction on the name.
+    TypoCorrection corrected = CorrectTypo(
+        DeclarationNameInfo(identifiers[i], identifierLocs[i]), lookupKind, S,
+        nullptr,
+        llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(Context,
+                                                             lookupKind),
+        CTK_ErrorRecovery);
+    if (corrected) {
+      // Did we find a protocol?
+      if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) {
+        diagnoseTypo(corrected,
+                     PDiag(diag::err_undeclared_protocol_suggest)
+                       << identifiers[i]);
+        lookupKind = LookupObjCProtocolName;
+        protocols[i] = proto;
+        ++numProtocolsResolved;
+        continue;
+      }
+
+      // Did we find a type?
+      if (auto typeDecl = corrected.getCorrectionDeclAs<TypeDecl>()) {
+        diagnoseTypo(corrected,
+                     PDiag(diag::err_unknown_typename_suggest)
+                       << identifiers[i]);
+        lookupKind = LookupOrdinaryName;
+        typeDecls[i] = typeDecl;
+        ++numTypeDeclsResolved;
+        continue;
+      }
+
+      // Did we find an Objective-C class?
+      if (auto objcClass = corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
+        diagnoseTypo(corrected,
+                     PDiag(diag::err_unknown_type_or_class_name_suggest)
+                       << identifiers[i] << true);
+        lookupKind = LookupOrdinaryName;
+        typeDecls[i] = objcClass;
+        ++numTypeDeclsResolved;
+        continue;
+      }
+    }
+
+    // We couldn't find anything.
+    Diag(identifierLocs[i],
+         (lookupKind == LookupAnyName ? diag::err_objc_type_arg_missing
+          : lookupKind == LookupObjCProtocolName ? diag::err_undeclared_protocol
+          : diag::err_unknown_typename))
+      << identifiers[i];
+    return;
+  }
+
+  // If all of the names were (corrected to) protocols, these were
+  // protocol qualifiers.
+  if (numProtocolsResolved == identifiers.size())
+    return resolvedAsProtocols();
+
+  // Otherwise, all of the names were (corrected to) types.
+  assert(numTypeDeclsResolved == identifiers.size() && "Not all types?");
+  return resolvedAsTypeDecls();
+}
+
 /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of
 /// a class method in its extension.
 ///
@@ -1374,8 +1760,9 @@ Decl *Sema::ActOnStartClassImplementatio
                                       true);
     IDecl->startDefinition();
     if (SDecl) {
-      IDecl->setSuperClass(SDecl);
-      IDecl->setSuperClassLoc(SuperClassLoc);
+      IDecl->setSuperClass(Context.getTrivialTypeSourceInfo(
+                             Context.getObjCInterfaceType(SDecl),
+                             SuperClassLoc));
       IDecl->setEndOfDefinitionLoc(SuperClassLoc);
     } else {
       IDecl->setEndOfDefinitionLoc(ClassLoc);

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jul  6 22:57:35 2015
@@ -5826,36 +5826,6 @@ static QualType checkConditionalPointerC
   return ResultTy;
 }
 
-/// \brief Returns true if QT is quelified-id and implements 'NSObject' and/or
-/// 'NSCopying' protocols (and nothing else); or QT is an NSObject and optionally
-/// implements 'NSObject' and/or NSCopying' protocols (and nothing else).
-static bool isObjCPtrBlockCompatible(Sema &S, ASTContext &C, QualType QT) {
-  if (QT->isObjCIdType())
-    return true;
-  
-  const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>();
-  if (!OPT)
-    return false;
-
-  if (ObjCInterfaceDecl *ID = OPT->getInterfaceDecl())
-    if (ID->getIdentifier() != &C.Idents.get("NSObject"))
-      return false;
-  
-  ObjCProtocolDecl* PNSCopying =
-    S.LookupProtocol(&C.Idents.get("NSCopying"), SourceLocation());
-  ObjCProtocolDecl* PNSObject =
-    S.LookupProtocol(&C.Idents.get("NSObject"), SourceLocation());
-
-  for (auto *Proto : OPT->quals()) {
-    if ((PNSCopying && declaresSameEntity(Proto, PNSCopying)) ||
-        (PNSObject && declaresSameEntity(Proto, PNSObject)))
-      ;
-    else
-      return false;
-  }
-  return true;
-}
-
 /// \brief Return the resulting type when the operands are both block pointers.
 static QualType checkConditionalBlockPointerCompatibility(Sema &S,
                                                           ExprResult &LHS,
@@ -7008,8 +6978,8 @@ Sema::CheckAssignmentConstraints(QualTyp
     }
 
     // Only under strict condition T^ is compatible with an Objective-C pointer.
-    if (RHSType->isBlockPointerType() &&
-        isObjCPtrBlockCompatible(*this, Context, LHSType)) {
+    if (RHSType->isBlockPointerType() && 
+        LHSType->isBlockCompatibleObjCPointerType(Context)) {
       maybeExtendBlockObject(*this, RHS);
       Kind = CK_BlockPointerToObjCPointerCast;
       return Compatible;

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Jul  6 22:57:35 2015
@@ -959,8 +959,10 @@ ExprResult Sema::BuildObjCDictionaryLite
               LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) {
             ObjCProtocolDecl *PQ[] = {NSCopyingPDecl};
             QIDNSCopying = 
-              Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
-                                        (ObjCProtocolDecl**) PQ,1);
+              Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { },
+                                        llvm::makeArrayRef(
+                                          (ObjCProtocolDecl**) PQ,
+                                          1));
             QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
           }
         }

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jul  6 22:57:35 2015
@@ -738,6 +738,160 @@ static void diagnoseAndRemoveTypeQualifi
   }
 }
 
+/// Apply Objective-C type arguments to the given type.
+static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
+                                  ArrayRef<ParsedType> typeArgs,
+                                  SourceRange typeArgsRange) {
+  // We can only apply type arguments to an Objective-C class type.
+  const auto *objcObjectType = type->getAs<ObjCObjectType>();
+  if (!objcObjectType || !objcObjectType->getInterface()) {
+    S.Diag(loc, diag::err_objc_type_args_non_class)
+      << type
+      << typeArgsRange;
+    return type;
+  }
+
+  // The class type must be parameterized.
+  ObjCInterfaceDecl *objcClass = objcObjectType->getInterface();
+  ObjCTypeParamList *typeParams = objcClass->getTypeParamList();
+  if (!typeParams) {
+    S.Diag(loc, diag::err_objc_type_args_non_parameterized_class)
+      << objcClass->getDeclName()
+      << FixItHint::CreateRemoval(typeArgsRange);
+    return type;
+  }
+
+  // The type must not already be specialized.
+  if (objcObjectType->isSpecialized()) {
+    S.Diag(loc, diag::err_objc_type_args_specialized_class)
+      << type
+      << FixItHint::CreateRemoval(typeArgsRange);
+    return type;
+  }
+
+  // Make sure that we have the right number of type arguments.
+  if (typeArgs.size() != typeParams->size()) {
+    S.Diag(loc, diag::err_objc_type_args_wrong_arity)
+      << (typeArgs.size() < typeParams->size())
+      << objcClass->getDeclName()
+      << (unsigned)typeArgs.size()
+      << (unsigned)typeParams->size();
+    S.Diag(objcClass->getLocation(), diag::note_previous_decl)
+      << objcClass;
+    return type;
+  }
+
+  // Check the type arguments.
+  SmallVector<QualType, 4> finalTypeArgs;
+  for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) {
+    TypeSourceInfo *typeArgInfo = nullptr;
+    QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo);
+    finalTypeArgs.push_back(typeArg);
+
+    // Objective-C object pointer types must be substitutable for the bounds.
+    if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) {
+      // Retrieve the bound.
+      ObjCTypeParamDecl *typeParam = typeParams->begin()[i];
+      QualType bound = typeParam->getUnderlyingType();
+      const auto *boundObjC = bound->getAs<ObjCObjectPointerType>();
+
+      // Determine whether the type argument is substitutable for the bound.
+      if (typeArgObjC->isObjCIdType()) {
+        // When the type argument is 'id', the only acceptable type
+        // parameter bound is 'id'.
+        if (boundObjC->isObjCIdType())
+          continue;
+      } else if (S.Context.canAssignObjCInterfaces(boundObjC, typeArgObjC)) {
+        // Otherwise, we follow the assignability rules.
+        continue;
+      }
+
+      // Diagnose the mismatch.
+      S.Diag(typeArgInfo->getTypeLoc().getLocStart(),
+             diag::err_objc_type_arg_does_not_match_bound)
+        << typeArg << bound << typeParam->getDeclName();
+      S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here)
+        << typeParam->getDeclName();
+
+      return type;
+    }
+
+    // Block pointer types are permitted for unqualified 'id' bounds.
+    if (typeArg->isBlockPointerType()) {
+      // Retrieve the bound.
+      ObjCTypeParamDecl *typeParam = typeParams->begin()[i];
+      QualType bound = typeParam->getUnderlyingType();
+      if (bound->isBlockCompatibleObjCPointerType(S.Context))
+        continue;
+
+      // Diagnose the mismatch.
+      S.Diag(typeArgInfo->getTypeLoc().getLocStart(),
+             diag::err_objc_type_arg_does_not_match_bound)
+        << typeArg << bound << typeParam->getDeclName();
+      S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here)
+        << typeParam->getDeclName();
+
+      return type;
+    }
+
+    // Dependent types will be checked at instantiation time.
+    if (typeArg->isDependentType()) {
+      continue;
+    }
+
+    // Diagnose non-id-compatible type arguments.
+    S.Diag(typeArgInfo->getTypeLoc().getLocStart(),
+           diag::err_objc_type_arg_not_id_compatible)
+      << typeArg
+      << typeArgInfo->getTypeLoc().getSourceRange();
+    return type;
+  }
+
+  // Success. Form the specialized type.
+  return S.Context.getObjCObjectType(type, finalTypeArgs, { });
+}
+
+/// Apply Objective-C protocol qualifiers to the given type.
+static QualType applyObjCProtocolQualifiers(
+                  Sema &S, SourceLocation loc, SourceRange range, QualType type,
+                  ArrayRef<ObjCProtocolDecl *> protocols,
+                  const SourceLocation *protocolLocs) {
+  ASTContext &ctx = S.Context;
+  if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){
+    // FIXME: Check for protocols to which the class type is already
+    // known to conform.
+
+    return ctx.getObjCObjectType(objT->getBaseType(),
+                                 objT->getTypeArgsAsWritten(),
+                                 protocols);
+  }
+
+  if (type->isObjCObjectType()) {
+    // Silently overwrite any existing protocol qualifiers.
+    // TODO: determine whether that's the right thing to do.
+
+    // FIXME: Check for protocols to which the class type is already
+    // known to conform.
+    return ctx.getObjCObjectType(type, { }, protocols);
+  }
+
+  // id<protocol-list>
+  if (type->isObjCIdType()) {
+    type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols);
+    return ctx.getObjCObjectPointerType(type);
+  }
+
+  // Class<protocol-list>
+  if (type->isObjCClassType()) {
+    type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols);
+    return ctx.getObjCObjectPointerType(type);
+  }
+
+  S.Diag(loc, diag::err_invalid_protocol_qualifiers)
+    << range;
+  return type;
+}
+
 /// \brief Convert the specified declspec to the appropriate type
 /// object.
 /// \param state Specifies the declarator containing the declaration specifier
@@ -803,9 +957,10 @@ static QualType ConvertDeclSpecToType(Ty
   case DeclSpec::TST_unspecified:
     // "<proto1,proto2>" is an objc qualified ID with a missing id.
     if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
-      Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
-                                         (ObjCProtocolDecl*const*)PQ,
-                                         DS.getNumProtocolQualifiers());
+      Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { },
+                                         llvm::makeArrayRef(
+                                           (ObjCProtocolDecl*const*)PQ,
+                                           DS.getNumProtocolQualifiers()));
       Result = Context.getObjCObjectPointerType(Result);
       break;
     }
@@ -967,37 +1122,8 @@ static QualType ConvertDeclSpecToType(Ty
            DS.getTypeSpecSign() == 0 &&
            "Can't handle qualifiers on typedef names yet!");
     Result = S.GetTypeFromParser(DS.getRepAsType());
-    if (Result.isNull())
+    if (Result.isNull()) {
       declarator.setInvalidType(true);
-    else if (DeclSpec::ProtocolQualifierListTy PQ
-               = DS.getProtocolQualifiers()) {
-      if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) {
-        // Silently drop any existing protocol qualifiers.
-        // TODO: determine whether that's the right thing to do.
-        if (ObjT->getNumProtocols())
-          Result = ObjT->getBaseType();
-
-        if (DS.getNumProtocolQualifiers())
-          Result = Context.getObjCObjectType(Result,
-                                             (ObjCProtocolDecl*const*) PQ,
-                                             DS.getNumProtocolQualifiers());
-      } else if (Result->isObjCIdType()) {
-        // id<protocol-list>
-        Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
-                                           (ObjCProtocolDecl*const*) PQ,
-                                           DS.getNumProtocolQualifiers());
-        Result = Context.getObjCObjectPointerType(Result);
-      } else if (Result->isObjCClassType()) {
-        // Class<protocol-list>
-        Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy,
-                                           (ObjCProtocolDecl*const*) PQ,
-                                           DS.getNumProtocolQualifiers());
-        Result = Context.getObjCObjectPointerType(Result);
-      } else {
-        S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers)
-          << DS.getSourceRange();
-        declarator.setInvalidType(true);
-      }
     } else if (S.getLangOpts().OpenCL) {
       if (const AtomicType *AT = Result->getAs<AtomicType>()) {
         const BuiltinType *BT = AT->getValueType()->getAs<BuiltinType>();
@@ -1022,6 +1148,21 @@ static QualType ConvertDeclSpecToType(Ty
           declarator.setInvalidType(true);
         }
       }
+    } else {
+      // Apply Objective-C type arguments.
+      if (DS.hasObjCTypeArgs()) {
+        Result = applyObjCTypeArgs(S, DeclLoc, Result, DS.getObjCTypeArgs(),
+                                   DS.getObjCTypeArgsRange());
+      }
+
+      // Apply Objective-C protocol qualifiers.
+      if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
+        Result = applyObjCProtocolQualifiers(
+                   S, DeclLoc, DS.getSourceRange(), Result,
+                   llvm::makeArrayRef((ObjCProtocolDecl * const *)PQ,
+                                      DS.getNumProtocolQualifiers()),
+                   DS.getProtocolLocs());
+      }
     }
 
     // TypeQuals handled by caller.
@@ -4138,18 +4279,33 @@ namespace {
         Visit(TL.getBaseLoc());
       }
 
+      // Type arguments.
+      if (TL.getNumTypeArgs() > 0) {
+        assert(TL.getNumTypeArgs() == DS.getObjCTypeArgs().size());
+        TL.setTypeArgsLAngleLoc(DS.getObjCTypeArgsLAngleLoc());
+        TL.setTypeArgsRAngleLoc(DS.getObjCTypeArgsRAngleLoc());
+        for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) {
+          TypeSourceInfo *typeArgInfo = nullptr;
+          (void)Sema::GetTypeFromParser(DS.getObjCTypeArgs()[i], &typeArgInfo);
+          TL.setTypeArgTInfo(i, typeArgInfo);
+        }
+      } else {
+        TL.setTypeArgsLAngleLoc(SourceLocation());
+        TL.setTypeArgsRAngleLoc(SourceLocation());
+      }
+
       // Protocol qualifiers.
       if (DS.getProtocolQualifiers()) {
         assert(TL.getNumProtocols() > 0);
         assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
-        TL.setLAngleLoc(DS.getProtocolLAngleLoc());
-        TL.setRAngleLoc(DS.getSourceRange().getEnd());
+        TL.setProtocolLAngleLoc(DS.getProtocolLAngleLoc());
+        TL.setProtocolRAngleLoc(DS.getSourceRange().getEnd());
         for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i)
           TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
       } else {
         assert(TL.getNumProtocols() == 0);
-        TL.setLAngleLoc(SourceLocation());
-        TL.setRAngleLoc(SourceLocation());
+        TL.setProtocolLAngleLoc(SourceLocation());
+        TL.setProtocolRAngleLoc(SourceLocation());
       }
     }
     void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Jul  6 22:57:35 2015
@@ -5263,11 +5263,15 @@ QualType ASTReader::readTypeRecord(unsig
   case TYPE_OBJC_OBJECT: {
     unsigned Idx = 0;
     QualType Base = readType(*Loc.F, Record, Idx);
+    unsigned NumTypeArgs = Record[Idx++];
+    SmallVector<QualType, 4> TypeArgs;
+    for (unsigned I = 0; I != NumTypeArgs; ++I)
+      TypeArgs.push_back(readType(*Loc.F, Record, Idx));
     unsigned NumProtos = Record[Idx++];
     SmallVector<ObjCProtocolDecl*, 4> Protos;
     for (unsigned I = 0; I != NumProtos; ++I)
       Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
-    return Context.getObjCObjectType(Base, Protos.data(), NumProtos);
+    return Context.getObjCObjectType(Base, TypeArgs, Protos);
   }
 
   case TYPE_OBJC_OBJECT_POINTER: {
@@ -5646,8 +5650,12 @@ void TypeLocReader::VisitObjCInterfaceTy
 }
 void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
   TL.setHasBaseTypeAsWritten(Record[Idx++]);
-  TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
-  TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
+  TL.setTypeArgsLAngleLoc(ReadSourceLocation(Record, Idx));
+  TL.setTypeArgsRAngleLoc(ReadSourceLocation(Record, Idx));
+  for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i)
+    TL.setTypeArgTInfo(i, Reader.GetTypeSourceInfo(F, Record, Idx));
+  TL.setProtocolLAngleLoc(ReadSourceLocation(Record, Idx));
+  TL.setProtocolRAngleLoc(ReadSourceLocation(Record, Idx));
   for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
     TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx));
 }

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Jul  6 22:57:35 2015
@@ -953,8 +953,7 @@ void ASTDeclReader::VisitObjCInterfaceDe
     ObjCInterfaceDecl::DefinitionData &Data = ID->data();
     
     // Read the superclass.
-    Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
-    Data.SuperClassLoc = ReadSourceLocation(Record, Idx);
+    Data.SuperClassTInfo = GetTypeSourceInfo(Record, Idx);
 
     Data.EndLoc = ReadSourceLocation(Record, Idx);
     Data.HasDesignatedInitializers = Record[Idx++];

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Jul  6 22:57:35 2015
@@ -421,6 +421,9 @@ void ASTTypeWriter::VisitObjCInterfaceTy
 
 void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
   Writer.AddTypeRef(T->getBaseType(), Record);
+  Record.push_back(T->getTypeArgs().size());
+  for (auto TypeArg : T->getTypeArgs())
+    Writer.AddTypeRef(TypeArg, Record);
   Record.push_back(T->getNumProtocols());
   for (const auto *I : T->quals())
     Writer.AddDeclRef(I, Record);
@@ -648,8 +651,12 @@ void TypeLocWriter::VisitObjCInterfaceTy
 }
 void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
   Record.push_back(TL.hasBaseTypeAsWritten());
-  Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
-  Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
+  Writer.AddSourceLocation(TL.getTypeArgsLAngleLoc(), Record);
+  Writer.AddSourceLocation(TL.getTypeArgsRAngleLoc(), Record);
+  for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i)
+    Writer.AddTypeSourceInfo(TL.getTypeArgTInfo(i), Record);
+  Writer.AddSourceLocation(TL.getProtocolLAngleLoc(), Record);
+  Writer.AddSourceLocation(TL.getProtocolRAngleLoc(), Record);
   for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
     Writer.AddSourceLocation(TL.getProtocolLoc(i), Record);
 }

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Mon Jul  6 22:57:35 2015
@@ -604,8 +604,7 @@ void ASTDeclWriter::VisitObjCInterfaceDe
     // Write the DefinitionData
     ObjCInterfaceDecl::DefinitionData &Data = D->data();
     
-    Writer.AddDeclRef(D->getSuperClass(), Record);
-    Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
+    Writer.AddTypeSourceInfo(D->getSuperClassTInfo(), Record);
     Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record);
     Record.push_back(Data.HasDesignatedInitializers);
 

Added: cfe/trunk/test/Index/annotate-parameterized-classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-parameterized-classes.m?rev=241542&view=auto
==============================================================================
--- cfe/trunk/test/Index/annotate-parameterized-classes.m (added)
+++ cfe/trunk/test/Index/annotate-parameterized-classes.m Mon Jul  6 22:57:35 2015
@@ -0,0 +1,42 @@
+ at protocol NSObject
+ at end
+
+ at interface NSObject
+ at end
+
+ at interface A<T : id, U : NSObject *> : NSObject
+ at end
+
+ at interface A<T : id, U : NSObject *> (Cat1)
+ at end
+
+typedef A<id<NSObject>, NSObject *> ASpecialization1;
+
+ at interface B<T : id, U : NSObject *> : A<T, U>
+ at end
+
+// RUN: c-index-test -test-annotate-tokens=%s:7:1:9:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-INTERFACE-DECL %s
+// CHECK-INTERFACE-DECL: Identifier: "T" [7:14 - 7:15] TemplateTypeParameter=T:7:14
+// FIXME: Should be a type reference
+// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TemplateTypeParameter=T:7:14
+// CHECK-INTERFACE-DECL: Identifier: "U" [7:22 - 7:23] TemplateTypeParameter=U:7:22
+// FIXME: Should be a class reference
+// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] TemplateTypeParameter=U:7:22
+
+// RUN: c-index-test -test-annotate-tokens=%s:10:1:12:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-CATEGORY-DECL %s
+// CHECK-CATEGORY-DECL: Identifier: "T" [10:14 - 10:15] TemplateTypeParameter=T:10:14 
+// FIXME: Should be a type reference
+// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TemplateTypeParameter=T:10:14
+// CHECK-CATEGORY-DECL: Identifier: "U" [10:22 - 10:23] TemplateTypeParameter=U:10:22
+// FIXME: Should be a class reference
+// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] TemplateTypeParameter=U:10:22
+
+// RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SPECIALIZATION %s
+// CHECK-SPECIALIZATION: Identifier: "id" [13:11 - 13:13] TypeRef=id:0:0
+// CHECK-SPECIALIZATION: Identifier: "NSObject" [13:14 - 13:22] ObjCProtocolRef=NSObject:1:11
+// CHECK-SPECIALIZATION: Identifier: "NSObject" [13:25 - 13:33] ObjCClassRef=NSObject:4:12
+
+// RUN: c-index-test -test-annotate-tokens=%s:15:1:16:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SUPER %s
+// CHECK-SUPER: Identifier: "A" [15:40 - 15:41] ObjCSuperClassRef=A:7:12
+// CHECK-SUPER: Identifier: "T" [15:42 - 15:43] TypeRef=T:15:14
+// CHECK-SUPER: Identifier: "U" [15:45 - 15:46] TypeRef=U:15:22

Modified: cfe/trunk/test/Index/complete-method-decls.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-method-decls.m?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-method-decls.m (original)
+++ cfe/trunk/test/Index/complete-method-decls.m Mon Jul  6 22:57:35 2015
@@ -208,8 +208,7 @@ typedef A *MyObjectRef;
 
 // RUN: c-index-test -code-completion-at=%s:85:2 %s | FileCheck -check-prefix=CHECK-CLASSTY %s
 // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text Class<P1>}{RightParen )}{TypedText meth}
-// FIXME: It should be "MyObject <P1> *""
-// CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text A<P1> *}{RightParen )}{TypedText meth2}
+// CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text MyObject<P1> *}{RightParen )}{TypedText meth2}
 // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text MyObjectRef}{RightParen )}{TypedText meth3}
 
 // RUN: c-index-test -code-completion-at=%s:93:2 %s | FileCheck -check-prefix=CHECK-NULLABILITY %s

Modified: cfe/trunk/test/PCH/objc_parameterized_classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_parameterized_classes.m?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/test/PCH/objc_parameterized_classes.m (original)
+++ cfe/trunk/test/PCH/objc_parameterized_classes.m Mon Jul  6 22:57:35 2015
@@ -19,6 +19,8 @@ __attribute__((objc_root_class))
 @interface PC1<T, U : NSObject *> (Cat1)
 @end
 
+typedef PC1<id, NSObject *> PC1Specialization1;
+
 #else
 
 @interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id}}
@@ -27,4 +29,6 @@ __attribute__((objc_root_class))
  // expected-note at 15{{type parameter 'U' declared here}}
 @end
 
+typedef PC1Specialization1<id, NSObject *> PC1Specialization2; // expected-error{{type arguments cannot be applied to already-specialized class type 'PC1Specialization1' (aka 'PC1<id,NSObject *>')}}
+
 #endif

Modified: cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm (original)
+++ cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm Mon Jul  6 22:57:35 2015
@@ -4,12 +4,7 @@
 template<class T> class vector {};
 @protocol P @end
 
-#if __cplusplus >= 201103L
-  // expected-no-diagnostics
-#else
-  // expected-error at 14{{a space is required between consecutive right angle brackets}}
-  // expected-error at 15{{a space is required between consecutive right angle brackets}}
-#endif
+// expected-no-diagnostics
 
 vector<id<P>> v;
 vector<vector<id<P>>> v2;

Modified: cfe/trunk/test/SemaObjC/interface-1.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/interface-1.m?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/interface-1.m (original)
+++ cfe/trunk/test/SemaObjC/interface-1.m Mon Jul  6 22:57:35 2015
@@ -3,7 +3,7 @@
 
 @interface NSWhatever :
 NSObject     // expected-error {{cannot find interface declaration for 'NSObject'}}
-<NSCopying>  // expected-error {{cannot find protocol declaration for 'NSCopying'}}
+<NSCopying>  // expected-error {{no type or protocol named 'NSCopying'}}
 @end
 
 

Modified: cfe/trunk/test/SemaObjC/parameterized_classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes.m?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/parameterized_classes.m (original)
+++ cfe/trunk/test/SemaObjC/parameterized_classes.m Mon Jul  6 22:57:35 2015
@@ -1,13 +1,16 @@
-// RUN: %clang_cc1 %s -verify
+// RUN: %clang_cc1 -fblocks %s -verify
 
- at protocol NSObject
+ at protocol NSObject // expected-note{{'NSObject' declared here}}
+ at end
+
+ at protocol NSCopying // expected-note{{'NSCopying' declared here}}
 @end
 
 __attribute__((objc_root_class))
 @interface NSObject <NSObject> // expected-note{{'NSObject' defined here}}
 @end
 
- at interface NSString : NSObject
+ at interface NSString : NSObject <NSCopying>
 @end
 
 // --------------------------------------------------------------------------
@@ -15,13 +18,14 @@ __attribute__((objc_root_class))
 // --------------------------------------------------------------------------
 
 // Parse type parameters with a bound
- at interface PC1<T, U : NSObject*> : NSObject
+ at interface PC1<T, U : NSObject*> : NSObject // expected-note{{'PC1' declared here}}
 // expected-note at -1{{type parameter 'T' declared here}}
 // expected-note at -2{{type parameter 'U' declared here}}
+// expected-note at -3{{type parameter 'U' declared here}}
 @end
 
 // Parse a type parameter with a bound that terminates in '>>'.
- at interface PC2<T : id<NSObject>> : NSObject // expected-error{{a space is required between consecutive right angle brackets (use '> >')}}
+ at interface PC2<T : id<NSObject>> : NSObject
 @end
 
 // Parse multiple type parameters.
@@ -29,11 +33,11 @@ __attribute__((objc_root_class))
 @end
 
 // Parse multiple type parameters--grammatically ambiguous with protocol refs.
- at interface PC4<T, U, V> : NSObject
+ at interface PC4<T, U, V> : NSObject // expected-note 2{{'PC4' declared here}}
 @end
 
 // Parse a type parameter list without a superclass.
- at interface PC5<T : id> // expected-error{{parameterized Objective-C class 'PC5' must have a superclass}}
+ at interface PC5<T : id>
 @end
 
 // Parse a type parameter with name conflicts.
@@ -92,6 +96,7 @@ __attribute__((objc_root_class))
 
 // Parameterized forward declaration a class that is not parameterized.
 @class NSObject<T>; // expected-error{{forward declaration of non-parameterized class 'NSObject' cannot have type parameters}}
+// expected-note at -1{{'NSObject' declared here}}
 
 // Parameterized forward declaration preceding the definition (that is
 // not parameterized).
@@ -190,3 +195,131 @@ void test_PC20_unspecialized(PC20 *pc20)
   ip = [pc20 extMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'X' (aka 'id')}}
   [pc20 extMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'Y' (aka 'NSObject *')}}
 }
+
+// --------------------------------------------------------------------------
+// Parsing type arguments.
+// --------------------------------------------------------------------------
+
+typedef NSString * ObjCStringRef; // expected-note{{'ObjCStringRef' declared here}}
+
+// Type arguments with a mix of identifiers and type-names.
+typedef PC4<id, NSObject *, NSString *> typeArgs1;
+
+// Type arguments with only identifiers.
+typedef PC4<id, id, id> typeArgs2;
+
+// Type arguments with only identifiers; one is ambiguous (resolved as
+// types).
+typedef PC4<NSObject, id, id> typeArgs3; // expected-error{{type argument 'NSObject' must be a pointer (requires a '*')}}
+
+// Type arguments with only identifiers; one is ambiguous (resolved as
+// protocol qualifiers).
+typedef PC4<NSObject, NSCopying> protocolQuals1;
+
+// Type arguments and protocol qualifiers.
+typedef PC4<id, NSObject *, id><NSObject, NSCopying> typeArgsAndProtocolQuals1;
+
+// Type arguments and protocol qualifiers in the wrong order.
+typedef PC4<NSObject, NSCopying><id, NSObject *, id> typeArgsAndProtocolQuals2; // expected-error{{protocol qualifiers must precede type arguments}}
+
+// Type arguments and protocol qualifiers (identifiers).
+typedef PC4<id, NSObject, id><NSObject, NSCopying> typeArgsAndProtocolQuals3; // expected-error{{type argument 'NSObject' must be a pointer (requires a '*')}}
+
+// Typo correction: protocol bias.
+typedef PC4<NSCopying, NSObjec> protocolQuals2; // expected-error{{cannot find protocol declaration for 'NSObjec'; did you mean 'NSObject'?}}
+
+// Typo correction: type bias.
+typedef PC4<id, id, NSObjec> typeArgs4; // expected-error{{unknown class name 'NSObjec'; did you mean 'NSObject'?}}
+// expected-error at -1{{type argument 'NSObject' must be a pointer (requires a '*')}}
+
+// Typo correction: bias set by correction itself to a protocol.
+typedef PC4<NSObject, NSObject, NSCopyin> protocolQuals3; // expected-error{{cannot find protocol declaration for 'NSCopyin'; did you mean 'NSCopying'?}}
+
+// Typo correction: bias set by correction itself to a type.
+typedef PC4<NSObject, NSObject, ObjCStringref> typeArgs5; // expected-error{{unknown type name 'ObjCStringref'; did you mean 'ObjCStringRef'?}}
+// expected-error at -1{{type argument 'NSObject' must be a pointer (requires a '*')}}
+// expected-error at -2{{type argument 'NSObject' must be a pointer (requires a '*')}}
+
+// Type/protocol conflict.
+typedef PC4<NSCopying, ObjCStringRef> typeArgsProtocolQualsConflict1; // expected-error{{angle brackets contain both a type ('ObjCStringRef') and a protocol ('NSCopying')}}
+
+// Handling the '>>' in type argument lists.
+typedef PC4<id<NSCopying>, NSObject *, id<NSObject>> typeArgs6;
+
+// --------------------------------------------------------------------------
+// Checking type arguments.
+// --------------------------------------------------------------------------
+
+ at interface PC15<T : id, U : NSObject *, V : id<NSCopying>> : NSObject
+// expected-note at -1{{type parameter 'V' declared here}}
+// expected-note at -2{{type parameter 'V' declared here}}
+// expected-note at -3{{type parameter 'U' declared here}}
+ at end
+
+typedef PC4<NSString *> tooFewTypeArgs1; // expected-error{{too few type arguments for class 'PC4' (have 1, expected 3)}}
+
+typedef PC4<NSString *, NSString *, NSString *, NSString *> tooManyTypeArgs1; // expected-error{{too many type arguments for class 'PC4' (have 4, expected 3)}}
+
+typedef PC15<int (^)(int, int), // block pointers as 'id'
+             NSString *, // subclass
+             NSString *> typeArgs7; // class that conforms to the protocol
+
+typedef PC15<NSObject *, NSObject *, id<NSCopying>> typeArgs8;
+
+typedef PC15<NSObject *, NSObject *,
+             NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}}
+
+typedef PC15<id,
+             id,  // expected-error{{type argument 'id' does not satisy the bound ('NSObject *') of type parameter 'U'}}
+             id> typeArgs9;
+
+typedef PC15<id, NSObject *,
+             id> typeArgs10; // expected-error{{type argument 'id' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}}
+
+typedef PC15<id,
+             int (^)(int, int), // okay
+             id<NSCopying, NSObject>> typeArgs11;
+
+typedef PC15<id, NSString *, int (^)(int, int)> typeArgs12; // okay
+
+typedef NSObject<id, id> typeArgs13; // expected-error{{type arguments cannot be applied to non-parameterized class 'NSObject'}}
+
+typedef id<id, id> typeArgs14; // expected-error{{type arguments cannot be applied to non-class type 'id'}}
+
+typedef PC1<NSObject *, NSString *> typeArgs15;
+
+typedef PC1<NSObject *, NSString *><NSCopying> typeArgsAndProtocolQuals4;
+
+typedef typeArgs15<NSCopying> typeArgsAndProtocolQuals5;
+
+typedef typeArgs15<NSObject *, NSString *> typeArgs16; // expected-error{{type arguments cannot be applied to already-specialized class type 'typeArgs15' (aka 'PC1<NSObject *,NSString *>')}}
+
+typedef typeArgs15<NSObject> typeArgsAndProtocolQuals6;
+
+void testSpecializedTypePrinting() {
+  int *ip;
+
+  ip = (typeArgs15*)0; // expected-warning{{'typeArgs15 *' (aka 'PC1<NSObject *,NSString *> *')}}
+  ip = (typeArgsAndProtocolQuals4*)0; // expected-warning{{'typeArgsAndProtocolQuals4 *' (aka 'PC1<NSObject *,NSString *><NSCopying> *')}}
+  ip = (typeArgsAndProtocolQuals5*)0; // expected-warning{{'typeArgsAndProtocolQuals5 *' (aka 'typeArgs15<NSCopying> *')}}
+  ip = (typeArgsAndProtocolQuals6)0; // expected-error{{used type 'typeArgsAndProtocolQuals6' (aka 'typeArgs15<NSObject>')}}
+  ip = (typeArgsAndProtocolQuals6*)0;// expected-warning{{'typeArgsAndProtocolQuals6 *' (aka 'typeArgs15<NSObject> *')}}
+}
+
+// --------------------------------------------------------------------------
+// Specialized superclasses
+// --------------------------------------------------------------------------
+ at interface PC21<T : NSObject *> : PC1<T, T>
+ at end
+
+ at interface PC22<T : NSObject *> : PC1<T> // expected-error{{too few type arguments for class 'PC1' (have 1, expected 2)}}
+ at end
+
+ at interface PC23<T : NSObject *> : PC1<T, U> // expected-error{{unknown type name 'U'}}
+ at end
+
+ at interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisy the bound ('NSObject *') of type parameter 'U'}}
+ at end
+
+ at interface NSFoo : PC1<NSObject *, NSObject *> // okay
+ at end

Added: cfe/trunk/test/SemaObjCXX/parameterized_classes.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/parameterized_classes.mm?rev=241542&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/parameterized_classes.mm (added)
+++ cfe/trunk/test/SemaObjCXX/parameterized_classes.mm Mon Jul  6 22:57:35 2015
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+// expected-no-diagnostics
+ at protocol NSObject
+ at end
+
+ at protocol NSCopying
+ at end
+
+__attribute__((objc_root_class))
+ at interface NSObject <NSObject>
+ at end
+
+ at interface NSString : NSObject
+ at end
+
+// --------------------------------------------------------------------------
+// Parsing parameterized classes.
+// --------------------------------------------------------------------------
+ at interface PC1<T, U, V> : NSObject
+ at end
+
+// --------------------------------------------------------------------------
+// Parsing type arguments.
+// --------------------------------------------------------------------------
+typedef PC1<::NSString *, NSString *, id<NSCopying>> typeArgs1;

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Mon Jul  6 22:57:35 2015
@@ -1021,6 +1021,9 @@ bool CursorVisitor::VisitObjCCategoryDec
                                    TU)))
     return true;
 
+  if (VisitObjCTypeParamList(ND->getTypeParamList()))
+    return true;
+
   ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin();
   for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(),
          E = ND->protocol_end(); I != E; ++I, ++PL)
@@ -1080,12 +1083,37 @@ bool CursorVisitor::VisitObjCPropertyDec
   return false;
 }
 
+bool CursorVisitor::VisitObjCTypeParamList(ObjCTypeParamList *typeParamList) {
+  if (!typeParamList)
+    return false;
+
+  for (auto *typeParam : *typeParamList) {
+    // Visit the type parameter.
+    if (Visit(MakeCXCursor(typeParam, TU, RegionOfInterest)))
+      return true;
+
+    // Visit the bound, if it's explicit.
+    if (typeParam->hasExplicitBound()) {
+      if (auto TInfo = typeParam->getTypeSourceInfo()) {
+        if (Visit(TInfo->getTypeLoc()))
+          return true;
+      }
+    }
+  }
+
+  return false;
+}
+
 bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
   if (!D->isThisDeclarationADefinition()) {
     // Forward declaration is treated like a reference.
     return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU));
   }
 
+  // Objective-C type parameters.
+  if (VisitObjCTypeParamList(D->getTypeParamListAsWritten()))
+    return true;
+
   // Issue callbacks for super class.
   if (D->getSuperClass() &&
       Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(),
@@ -1093,6 +1121,10 @@ bool CursorVisitor::VisitObjCInterfaceDe
                                         TU)))
     return true;
 
+  if (TypeSourceInfo *SuperClassTInfo = D->getSuperClassTInfo())
+    if (Visit(SuperClassTInfo->getTypeLoc()))
+      return true;
+
   ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin();
   for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
          E = D->protocol_end(); I != E; ++I, ++PL)
@@ -1486,6 +1518,11 @@ bool CursorVisitor::VisitObjCObjectTypeL
   if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc()))
     return true;
 
+  for (unsigned I = 0, N = TL.getNumTypeArgs(); I != N; ++I) {
+    if (Visit(TL.getTypeArgTInfo(I)->getTypeLoc()))
+      return true;
+  }
+
   for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
     if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I),
                                         TU)))
@@ -4411,7 +4448,12 @@ static enum CXChildVisitResult GetCursor
     *BestCursor = getTypeRefedCallExprCursor(*BestCursor);
     return CXChildVisit_Recurse;
   }
-  
+
+  // If we already have an Objective-C superclass reference, don't
+  // update it further.
+  if (BestCursor->kind == CXCursor_ObjCSuperClassRef)
+    return CXChildVisit_Break;
+
   *BestCursor = cursor;
   return CXChildVisit_Recurse;
 }

Modified: cfe/trunk/tools/libclang/CursorVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CursorVisitor.h?rev=241542&r1=241541&r2=241542&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CursorVisitor.h (original)
+++ cfe/trunk/tools/libclang/CursorVisitor.h Mon Jul  6 22:57:35 2015
@@ -222,6 +222,7 @@ public:
   bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
   bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
   bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD);
+  bool VisitObjCTypeParamList(ObjCTypeParamList *typeParamList);
   bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
   bool VisitObjCImplDecl(ObjCImplDecl *D);
   bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);





More information about the cfe-commits mailing list