r241542 - Handle Objective-C type arguments.

Justin Bogner mail at justinbogner.com
Wed Jul 8 11:32:53 PDT 2015


Douglas Gregor <dgregor at apple.com> writes:
> 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) {

According to ubsan, ShouldAKA is evaluated uninitialized here. In fact,
only one of the two non-recursive callers bother initializing it, but
until now we never read the value within Desugar.

I've gone ahead and fixed this in r241705. Please take a look.

> +      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);
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list