r241541 - Parsing, semantic analysis, and AST for Objective-C type parameters.

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


Author: dgregor
Date: Mon Jul  6 22:57:15 2015
New Revision: 241541

URL: http://llvm.org/viewvc/llvm-project?rev=241541&view=rev
Log:
Parsing, semantic analysis, and AST for Objective-C type parameters.

Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.

Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.

Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.

Part of rdar://problem/6294649.

Added:
    cfe/trunk/test/Index/comment-objc-parameterized-classes.m
    cfe/trunk/test/PCH/objc_parameterized_classes.m
    cfe/trunk/test/SemaObjC/parameterized_classes.m
Modified:
    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/Basic/DeclNodes.td
    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/Sema.h
    cfe/trunk/include/clang/Sema/Template.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/ASTDumper.cpp
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/AST/DeclObjC.cpp
    cfe/trunk/lib/AST/DeclPrinter.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Serialization/ASTCommon.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/Parser/objc-error-qualified-implementation.m
    cfe/trunk/tools/libclang/CIndex.cpp

Modified: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h Mon Jul  6 22:57:15 2015
@@ -1307,7 +1307,12 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDec
                                            })
 
 DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
-                                    })
+  if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
+    for (auto typeParam : *typeParamList)
+      TRY_TO(TraverseObjCTypeParamDecl(typeParam));
+  }
+  return true;
+})
 
 DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
                                         })
@@ -1316,7 +1321,12 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl
                                           })
 
 DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
-                                     })
+  if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
+    for (auto typeParam : *typeParamList)
+      TRY_TO(TraverseObjCTypeParamDecl(typeParam));
+  }
+  return true;
+})
 
 DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
                                     })
@@ -1335,6 +1345,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
   return true;
 })
 
+DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
+  if (D->hasExplicitBound()) {
+    TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+    // We shouldn't traverse D->getTypeForDecl(); it's a result of
+    // declaring the type alias, not something that was written in the
+    // source.
+  }
+})
+
 DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
   if (D->getTypeSourceInfo())
     TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Mon Jul  6 22:57:15 2015
@@ -501,6 +501,124 @@ public:
   friend class ASTDeclWriter;
 };
 
+/// Represents the declaration of an Objective-C type parameter.
+///
+/// \code
+/// @interface NSDictionary<Key : id<NSCopying>, Value>
+/// @end
+/// \endcode
+///
+/// In the example above, both \c Key and \c Value are represented by
+/// \c ObjCTypeParamDecl. \c Key has an explicit bound of \c id<NSCopying>,
+/// while \c Value gets an implicit bound of \c id.
+///
+/// Objective-C type parameters are typedef-names in the grammar,
+class ObjCTypeParamDecl : public TypedefNameDecl {
+  void anchor() override;
+
+  // The location of the ':', which will be valid when the bound was
+  // explicitly specified.
+  SourceLocation ColonLoc;
+
+  ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc,
+                    SourceLocation nameLoc, IdentifierInfo *name,
+                    SourceLocation colonLoc, TypeSourceInfo *boundInfo)
+    : TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name,
+                      boundInfo),
+      ColonLoc(colonLoc) { }
+
+public:
+  static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc,
+                                   SourceLocation nameLoc,
+                                   IdentifierInfo *name,
+                                   SourceLocation colonLoc,
+                                   TypeSourceInfo *boundInfo);
+  static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID);
+
+  SourceRange getSourceRange() const override LLVM_READONLY;
+
+  /// Whether this type parameter has an explicitly-written type bound, e.g.,
+  /// "T : NSView".
+  bool hasExplicitBound() const { return ColonLoc.isValid(); }
+
+  /// Retrieve the location of the ':' separating the type parameter name
+  /// from the explicitly-specified bound.
+  SourceLocation getColonLoc() const { return ColonLoc; }
+
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+  static bool classofKind(Kind K) { return K == ObjCTypeParam; }
+
+  friend class ASTDeclReader;
+  friend class ASTDeclWriter;
+};
+
+/// Stores a list of Objective-C type parameters for a parameterized class
+/// or a category/extension thereof.
+///
+/// \code
+/// @interface NSArray<T> // stores the <T>
+/// @end
+/// \endcode
+class ObjCTypeParamList {
+  union { 
+    /// Location of the left and right angle brackets.
+    SourceRange Brackets;
+
+    // Used only for alignment.
+    ObjCTypeParamDecl *AlignmentHack;
+  };
+
+  /// The number of parameters in the list, which are tail-allocated.
+  unsigned NumParams;
+
+  ObjCTypeParamList(SourceLocation lAngleLoc,
+                    ArrayRef<ObjCTypeParamDecl *> typeParams,
+                    SourceLocation rAngleLoc);
+
+public:
+  /// Create a new Objective-C type parameter list.
+  static ObjCTypeParamList *create(ASTContext &ctx,
+                                   SourceLocation lAngleLoc,
+                                   ArrayRef<ObjCTypeParamDecl *> typeParams,
+                                   SourceLocation rAngleLoc);
+
+  /// Iterate through the type parameters in the list.
+  typedef ObjCTypeParamDecl **iterator;
+
+  iterator begin() { return reinterpret_cast<ObjCTypeParamDecl **>(this + 1); }
+
+  iterator end() { return begin() + size(); }
+
+  /// Determine the number of type parameters in this list.
+  unsigned size() const { return NumParams; }
+
+  // Iterate through the type parameters in the list.
+  typedef ObjCTypeParamDecl * const *const_iterator;
+
+  const_iterator begin() const {
+    return reinterpret_cast<ObjCTypeParamDecl * const *>(this + 1);
+  }
+
+  const_iterator end() const {
+    return begin() + size();
+  }
+
+  ObjCTypeParamDecl *front() const {
+    assert(size() > 0 && "empty Objective-C type parameter list");
+    return *begin();
+  }
+
+  ObjCTypeParamDecl *back() const {
+    assert(size() > 0 && "empty Objective-C type parameter list");
+    return *(end() - 1);
+  }
+
+  SourceLocation getLAngleLoc() const { return Brackets.getBegin(); }
+  SourceLocation getRAngleLoc() const { return Brackets.getEnd(); }
+  SourceRange getSourceRange() const { return Brackets; }
+};
+
 /// ObjCContainerDecl - Represents a container for method declarations.
 /// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl,
 /// ObjCProtocolDecl, and ObjCImplDecl.
@@ -736,11 +854,15 @@ class ObjCInterfaceDecl : public ObjCCon
   };
 
   ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
-                    IdentifierInfo *Id, SourceLocation CLoc,
-                    ObjCInterfaceDecl *PrevDecl, bool IsInternal);
+                    IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
+                    SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
+                    bool IsInternal);
 
   void LoadExternalDefinition() const;
 
+  /// The type parameters associated with this class, if any.
+  ObjCTypeParamList *TypeParamList;
+
   /// \brief Contains a pointer to the data associated with this class,
   /// which will be NULL if this class has not yet been defined.
   ///
@@ -771,12 +893,27 @@ public:
   static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC,
                                    SourceLocation atLoc,
                                    IdentifierInfo *Id,
+                                   ObjCTypeParamList *typeParamList,
                                    ObjCInterfaceDecl *PrevDecl,
                                    SourceLocation ClassLoc = SourceLocation(),
                                    bool isInternal = false);
 
   static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
 
+  /// 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
+  /// has type parameters, skipping any declarations that do not.
+  ObjCTypeParamList *getTypeParamList() const;
+
+  /// Retrieve the type parameters written on this particular declaration of
+  /// the class.
+  ObjCTypeParamList *getTypeParamListAsWritten() const {
+    return TypeParamList;
+  }
+
   SourceRange getSourceRange() const override LLVM_READONLY {
     if (isThisDeclarationADefinition())
       return ObjCContainerDecl::getSourceRange();
@@ -1719,6 +1856,9 @@ class ObjCCategoryDecl : public ObjCCont
   /// Interface belonging to this category
   ObjCInterfaceDecl *ClassInterface;
 
+  /// The type parameters associated with this category, if any.
+  ObjCTypeParamList *TypeParamList;
+
   /// referenced protocols in this category.
   ObjCProtocolList ReferencedProtocols;
 
@@ -1736,13 +1876,9 @@ class ObjCCategoryDecl : public ObjCCont
   ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
                    SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
                    IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
+                   ObjCTypeParamList *typeParamList,
                    SourceLocation IvarLBraceLoc=SourceLocation(),
-                   SourceLocation IvarRBraceLoc=SourceLocation())
-    : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
-      ClassInterface(IDecl), NextClassCategory(nullptr),
-      CategoryNameLoc(CategoryNameLoc),
-      IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
-  }
+                   SourceLocation IvarRBraceLoc=SourceLocation());
 
 public:
 
@@ -1752,6 +1888,7 @@ public:
                                   SourceLocation CategoryNameLoc,
                                   IdentifierInfo *Id,
                                   ObjCInterfaceDecl *IDecl,
+                                  ObjCTypeParamList *typeParamList,
                                   SourceLocation IvarLBraceLoc=SourceLocation(),
                                   SourceLocation IvarRBraceLoc=SourceLocation());
   static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -1759,6 +1896,10 @@ public:
   ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
   const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
 
+  /// Retrieve the type parameter list associated with this category or
+  /// extension.
+  ObjCTypeParamList *getTypeParamList() const { return TypeParamList; }
+
   ObjCCategoryImplDecl *getImplementation() const;
   void setImplementation(ObjCCategoryImplDecl *ImplD);
 

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Mon Jul  6 22:57:15 2015
@@ -1382,7 +1382,11 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDec
                                            })
 
 DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
-                                    })
+  if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
+    for (auto typeParam : *typeParamList)
+      TRY_TO(TraverseObjCTypeParamDecl(typeParam));
+  }
+})
 
 DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
                                         })
@@ -1391,7 +1395,11 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl
                                           })
 
 DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
-                                     })
+  if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
+    for (auto typeParam : *typeParamList)
+      TRY_TO(TraverseObjCTypeParamDecl(typeParam));
+  }
+})
 
 DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
                                     })
@@ -1410,6 +1418,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
   return true;
 })
 
+DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
+  if (D->hasExplicitBound()) {
+    TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+    // We shouldn't traverse D->getTypeForDecl(); it's a result of
+    // declaring the type alias, not something that was written in the
+    // source.
+  }
+})
+
 DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
   if (D->getTypeSourceInfo())
     TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));

Modified: cfe/trunk/include/clang/Basic/DeclNodes.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DeclNodes.td?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DeclNodes.td (original)
+++ cfe/trunk/include/clang/Basic/DeclNodes.td Mon Jul  6 22:57:15 2015
@@ -21,6 +21,7 @@ def Named : Decl<1>;
     def TypedefName : DDecl<Type, 1>;
       def Typedef : DDecl<TypedefName>;
       def TypeAlias : DDecl<TypedefName>;
+      def ObjCTypeParam : DDecl<TypedefName>;
     def UnresolvedUsingTypename : DDecl<Type>;
     def Tag : DDecl<Type, 1>, DeclContext;
       def Enum : DDecl<Tag>;

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Jul  6 22:57:15 2015
@@ -1017,4 +1017,17 @@ def err_module_expected_semi : Error<
   "expected ';' after module name">;
 }
 
+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">;
+
+}
+
 } // 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=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul  6 22:57:15 2015
@@ -7743,6 +7743,42 @@ def warn_nullability_missing : Warning<
   "%select{pointer|block pointer|member pointer}0 is missing a nullability "
   "type specifier (_Nonnull, _Nullable, or _Null_unspecified)">,
   InGroup<NullabilityCompleteness>;
+}
+
+let CategoryName = "Generics Issue" in {
+
+def err_objc_type_param_bound_nonobject : Error<
+  "type bound %0 for type parameter %1 is not an Objective-C pointer type">;
+
+def err_objc_type_param_bound_missing_pointer : Error<
+  "missing '*' in type bound %0 for type parameter %1">;
+
+def err_objc_type_param_redecl : Error<
+  "redeclaration of type parameter %0">;
+
+def err_objc_type_param_arity_mismatch : Error<
+  "%select{forward class declaration|class definition|category|extension}0 has "
+  "too %select{few|many}1 type parameters (expected %2, have %3)">;
+
+def err_objc_type_param_bound_conflict : Error<
+  "type bound %0 for type parameter %1 conflicts with "
+  "%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">;
+
+def note_objc_type_param_here : Note<"type parameter %0 declared here">;
+
+def err_objc_type_param_bound_missing : Error<
+  "missing type bound %0 for type parameter %1 in %select{@interface|@class}2">;
+
+def err_objc_parameterized_category_nonclass : Error<
+  "%select{extension|category}0 of non-parameterized class %1 cannot have type "
+  "parameters">;
+
+def err_objc_parameterized_forward_class : Error<
+  "forward declaration of non-parameterized class %0 cannot have type "
+  "parameters">;
+
+def err_objc_parameterized_forward_class_first : Error<
+  "class %0 previously declared with type parameters">;
 
 }
 

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul  6 22:57:15 2015
@@ -46,6 +46,8 @@ namespace clang {
   class PoisonSEHIdentifiersRAIIObject;
   class VersionTuple;
   class OMPClause;
+  class ObjCTypeParamList;
+  class ObjCTypeParameter;
 
 /// Parser - This implements a parser for the C family of languages.  After
 /// parsing units of the grammar, productions are invoked to handle whatever has
@@ -1246,6 +1248,13 @@ private:
   DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
   Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
                                         ParsedAttributes &prefixAttrs);
+  ObjCTypeParamList *parseObjCTypeParamList();
+  ObjCTypeParamList *parseObjCTypeParamListOrProtocolRefs(
+                           SourceLocation &lAngleLoc,
+                           SmallVectorImpl<IdentifierLocPair> &protocolIdents,
+                           SourceLocation &rAngleLoc,
+                           bool mayBeProtocolList = true);
+
   void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
                                         BalancedDelimiterTracker &T,
                                         SmallVectorImpl<Decl *> &AllIvarDecls,
@@ -2469,7 +2478,8 @@ private:
   typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
 
   bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
-                                      bool ConsumeLastToken);
+                                      bool ConsumeLastToken,
+                                      bool ObjCGenericList);
   bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
                                         SourceLocation TemplateNameLoc,
                                         const CXXScopeSpec &SS,

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul  6 22:57:15 2015
@@ -7088,9 +7088,20 @@ public:
   };
   ObjCContainerKind getObjCContainerKind() const;
 
+  DeclResult actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
+                                SourceLocation paramLoc,
+                                SourceLocation colonLoc,
+                                ParsedType typeBound);
+
+  ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc,
+                                            ArrayRef<Decl *> typeParams,
+                                            SourceLocation rAngleLoc);
+  void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList);
+
   Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
                                  IdentifierInfo *ClassName,
                                  SourceLocation ClassLoc,
+                                 ObjCTypeParamList *typeParamList,
                                  IdentifierInfo *SuperName,
                                  SourceLocation SuperLoc,
                                  Decl * const *ProtoRefs,
@@ -7124,6 +7135,7 @@ public:
   Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
                                     IdentifierInfo *ClassName,
                                     SourceLocation ClassLoc,
+                                    ObjCTypeParamList *typeParamList,
                                     IdentifierInfo *CategoryName,
                                     SourceLocation CategoryLoc,
                                     Decl * const *ProtoRefs,
@@ -7147,9 +7159,10 @@ public:
                                                ArrayRef<Decl *> Decls);
 
   DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
-                                     IdentifierInfo **IdentList,
-                                     SourceLocation *IdentLocs,
-                                     unsigned NumElts);
+                   IdentifierInfo **IdentList,
+                   SourceLocation *IdentLocs,
+                   ArrayRef<ObjCTypeParamList *> TypeParamLists,
+                   unsigned NumElts);
 
   DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
                                         const IdentifierLocPair *IdentList,

Modified: cfe/trunk/include/clang/Sema/Template.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Template.h (original)
+++ cfe/trunk/include/clang/Sema/Template.h Mon Jul  6 22:57:15 2015
@@ -413,6 +413,7 @@ namespace clang {
 #define LINKAGESPEC(DERIVED, BASE)
 #define OBJCCOMPATIBLEALIAS(DERIVED, BASE)
 #define OBJCMETHOD(DERIVED, BASE)
+#define OBJCTYPEPARAM(DERIVED, BASE)
 #define OBJCIVAR(DERIVED, BASE)
 #define OBJCPROPERTY(DERIVED, BASE)
 #define OBJCPROPERTYIMPL(DERIVED, BASE)

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Mon Jul  6 22:57:15 2015
@@ -1105,7 +1105,9 @@ namespace clang {
       /// \brief An OMPThreadPrivateDecl record.
       DECL_OMP_THREADPRIVATE,
       /// \brief An EmptyDecl record.
-      DECL_EMPTY
+      DECL_EMPTY,
+      /// \brief An ObjCTypeParamDecl record.
+      DECL_OBJC_TYPE_PARAM,
     };
 
     /// \brief Record codes for each kind of statement or expression.

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Jul  6 22:57:15 2015
@@ -5951,6 +5951,7 @@ ObjCInterfaceDecl *ASTContext::getObjCPr
       = ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(), 
                                   SourceLocation(),
                                   &Idents.get("Protocol"),
+                                  /*typeParamList=*/nullptr,
                                   /*PrevDecl=*/nullptr,
                                   SourceLocation(), true);    
   }

Modified: cfe/trunk/lib/AST/ASTDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTDumper.cpp (original)
+++ cfe/trunk/lib/AST/ASTDumper.cpp Mon Jul  6 22:57:15 2015
@@ -240,6 +240,9 @@ namespace  {
     void dumpTemplateArgument(const TemplateArgument &A,
                               SourceRange R = SourceRange());
 
+    // Objective-C utilities.
+    void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams);
+
     // Types
     void VisitComplexType(const ComplexType *T) {
       dumpTypeAsChild(T->getElementType());
@@ -463,6 +466,7 @@ namespace  {
     // ObjC Decls
     void VisitObjCIvarDecl(const ObjCIvarDecl *D);
     void VisitObjCMethodDecl(const ObjCMethodDecl *D);
+    void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
     void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
     void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
     void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
@@ -955,6 +959,18 @@ void ASTDumper::dumpTemplateArgument(con
 }
 
 //===----------------------------------------------------------------------===//
+//  Objective-C Utilities
+//===----------------------------------------------------------------------===//
+void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
+  if (!typeParams)
+    return;
+
+  for (auto typeParam : *typeParams) {
+    dumpDecl(typeParam);
+  }
+}
+
+//===----------------------------------------------------------------------===//
 //  Decl dumping methods.
 //===----------------------------------------------------------------------===//
 
@@ -1457,9 +1473,17 @@ void ASTDumper::VisitObjCMethodDecl(cons
     dumpStmt(D->getBody());
 }
 
+void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
+  dumpName(D);
+  if (D->hasExplicitBound())
+    OS << " bounded";
+  dumpType(D->getUnderlyingType());
+}
+
 void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
   dumpName(D);
   dumpDeclRef(D->getClassInterface());
+  dumpObjCTypeParamList(D->getTypeParamList());
   dumpDeclRef(D->getImplementation());
   for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
                                            E = D->protocol_end();
@@ -1482,6 +1506,7 @@ void ASTDumper::VisitObjCProtocolDecl(co
 
 void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
   dumpName(D);
+  dumpObjCTypeParamList(D->getTypeParamListAsWritten());
   dumpDeclRef(D->getSuperClass(), "super");
 
   dumpDeclRef(D->getImplementation());

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Jul  6 22:57:15 2015
@@ -150,9 +150,12 @@ namespace clang {
     Decl *VisitImplicitParamDecl(ImplicitParamDecl *D);
     Decl *VisitParmVarDecl(ParmVarDecl *D);
     Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
+    Decl *VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
     Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D);
     Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
     Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D);
+
+    ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list);
     Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
     Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
     Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
@@ -3423,6 +3426,32 @@ Decl *ASTNodeImporter::VisitObjCMethodDe
   return ToMethod;
 }
 
+Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
+  // Import the major distinguishing characteristics of a category.
+  DeclContext *DC, *LexicalDC;
+  DeclarationName Name;
+  SourceLocation Loc;
+  NamedDecl *ToD;
+  if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
+    return nullptr;
+  if (ToD)
+    return ToD;
+
+  TypeSourceInfo *BoundInfo = Importer.Import(D->getTypeSourceInfo());
+  if (!BoundInfo)
+    return nullptr;
+
+  ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create(
+                                Importer.getToContext(), DC,
+                                Importer.Import(D->getLocation()),
+                                Name.getAsIdentifierInfo(),
+                                Importer.Import(D->getColonLoc()),
+                                BoundInfo);
+  Importer.Imported(D, Result);
+  Result->setLexicalDeclContext(LexicalDC);
+  return Result;
+}
+
 Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
   // Import the major distinguishing characteristics of a category.
   DeclContext *DC, *LexicalDC;
@@ -3450,6 +3479,8 @@ Decl *ASTNodeImporter::VisitObjCCategory
                                        Importer.Import(D->getCategoryNameLoc()), 
                                           Name.getAsIdentifierInfo(),
                                           ToInterface,
+                                          ImportObjCTypeParamList(
+                                            D->getTypeParamList()),
                                        Importer.Import(D->getIvarLBraceLoc()),
                                        Importer.Import(D->getIvarRBraceLoc()));
     ToCategory->setLexicalDeclContext(LexicalDC);
@@ -3716,6 +3747,27 @@ bool ASTNodeImporter::ImportDefinition(O
   return false;
 }
 
+ObjCTypeParamList *
+ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) {
+  if (!list)
+    return nullptr;
+
+  SmallVector<ObjCTypeParamDecl *, 4> toTypeParams;
+  for (auto fromTypeParam : *list) {
+    auto toTypeParam = cast_or_null<ObjCTypeParamDecl>(
+                         Importer.Import(fromTypeParam));
+    if (!toTypeParam)
+      return nullptr;
+
+    toTypeParams.push_back(toTypeParam);
+  }
+
+  return ObjCTypeParamList::create(Importer.getToContext(),
+                                   Importer.Import(list->getLAngleLoc()),
+                                   toTypeParams,
+                                   Importer.Import(list->getRAngleLoc()));
+}
+
 Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
   // If this class has a definition in the translation unit we're coming from,
   // but this particular declaration is not that definition, import the
@@ -3756,7 +3808,9 @@ Decl *ASTNodeImporter::VisitObjCInterfac
   if (!ToIface) {
     ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
                                         Importer.Import(D->getAtStartLoc()),
-                                        Name.getAsIdentifierInfo(), 
+                                        Name.getAsIdentifierInfo(),
+                                        ImportObjCTypeParamList(
+                                          D->getTypeParamListAsWritten()),
                                         /*PrevDecl=*/nullptr, Loc,
                                         D->isImplicitInterfaceDecl());
     ToIface->setLexicalDeclContext(LexicalDC);

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Mon Jul  6 22:57:15 2015
@@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceFor
     case TypeAliasTemplate:
     case UnresolvedUsingTypename:
     case TemplateTypeParm:
+    case ObjCTypeParam:
       return IDNS_Ordinary | IDNS_Type;
 
     case UsingShadow:

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Mon Jul  6 22:57:15 2015
@@ -239,6 +239,26 @@ ObjCPropertyDecl *ObjCContainerDecl::Fin
 
 void ObjCInterfaceDecl::anchor() { }
 
+ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const {
+  // If this particular declaration has a type parameter list, return it.
+  if (ObjCTypeParamList *written = getTypeParamListAsWritten())
+    return written;
+
+  // If there is a definition, return its type parameter list.
+  if (const ObjCInterfaceDecl *def = getDefinition())
+    return def->getTypeParamListAsWritten();
+
+  // Otherwise, look at previous declarations to determine whether any
+  // of them has a type parameter list, skipping over those
+  // declarations that do not.
+  for (auto decl = getPreviousDecl(); decl; decl = decl->getPreviousDecl()) {
+    if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten())
+      return written;
+  }
+
+  return nullptr;
+}
+
 /// 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.
@@ -1137,6 +1157,62 @@ ObjCMethodDecl::findPropertyDecl(bool Ch
 }
 
 //===----------------------------------------------------------------------===//
+// ObjCTypeParamDecl
+//===----------------------------------------------------------------------===//
+
+void ObjCTypeParamDecl::anchor() { }
+
+ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc,
+                                             SourceLocation nameLoc,
+                                             IdentifierInfo *name,
+                                             SourceLocation colonLoc,
+                                             TypeSourceInfo *boundInfo) {
+  return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, nameLoc, name, colonLoc,
+                                         boundInfo);
+}
+
+ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
+                                                         unsigned ID) {
+  return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, SourceLocation(),
+                                         nullptr, SourceLocation(), nullptr);
+}
+
+SourceRange ObjCTypeParamDecl::getSourceRange() const {
+  if (hasExplicitBound()) {
+    return SourceRange(getLocation(),
+                       getTypeSourceInfo()->getTypeLoc().getEndLoc());
+  }
+
+  return SourceRange(getLocation());
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCTypeParamList
+//===----------------------------------------------------------------------===//
+ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc,
+                                     ArrayRef<ObjCTypeParamDecl *> typeParams,
+                                     SourceLocation rAngleLoc)
+  : Brackets(lAngleLoc, rAngleLoc), NumParams(typeParams.size())
+{
+  std::copy(typeParams.begin(), typeParams.end(), begin());
+}
+
+
+ObjCTypeParamList *ObjCTypeParamList::create(
+                     ASTContext &ctx,
+                     SourceLocation lAngleLoc,
+                     ArrayRef<ObjCTypeParamDecl *> typeParams,
+                     SourceLocation rAngleLoc) {
+  unsigned size = sizeof(ObjCTypeParamList)
+                + sizeof(ObjCTypeParamDecl *) * typeParams.size();
+  static_assert(alignof(ObjCTypeParamList) >= alignof(ObjCTypeParamDecl*),
+                "type parameter list needs greater alignment");
+  unsigned align = llvm::alignOf<ObjCTypeParamList>();
+  void *mem = ctx.Allocate(size, align);
+  return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc);
+}
+
+//===----------------------------------------------------------------------===//
 // ObjCInterfaceDecl
 //===----------------------------------------------------------------------===//
 
@@ -1144,11 +1220,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Cr
                                              DeclContext *DC,
                                              SourceLocation atLoc,
                                              IdentifierInfo *Id,
+                                             ObjCTypeParamList *typeParamList,
                                              ObjCInterfaceDecl *PrevDecl,
                                              SourceLocation ClassLoc,
                                              bool isInternal){
   ObjCInterfaceDecl *Result = new (C, DC)
-      ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal);
+      ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
+                        isInternal);
   Result->Data.setInt(!C.getLangOpts().Modules);
   C.getObjCInterfaceType(Result, PrevDecl);
   return Result;
@@ -1159,6 +1237,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Cr
   ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr,
                                                             SourceLocation(),
                                                             nullptr,
+                                                            nullptr,
                                                             SourceLocation(),
                                                             nullptr, false);
   Result->Data.setInt(!C.getLangOpts().Modules);
@@ -1167,11 +1246,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Cr
 
 ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
                                      SourceLocation AtLoc, IdentifierInfo *Id,
+                                     ObjCTypeParamList *typeParamList,
                                      SourceLocation CLoc,
                                      ObjCInterfaceDecl *PrevDecl,
                                      bool IsInternal)
     : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
-      redeclarable_base(C), TypeForDecl(nullptr), Data() {
+      redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(typeParamList),
+      Data() {
   setPreviousDecl(PrevDecl);
   
   // Copy the 'data' pointer over.
@@ -1179,6 +1260,12 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(con
     Data = PrevDecl->Data;
   
   setImplicit(IsInternal);
+
+  // Update the declaration context of the type parameters.
+  if (typeParamList) {
+    for (auto typeParam : *typeParamList)
+      typeParam->setDeclContext(this);
+  }
 }
 
 void ObjCInterfaceDecl::LoadExternalDefinition() const {
@@ -1648,17 +1735,39 @@ ObjCProtocolDecl::getObjCRuntimeNameAsSt
 
 void ObjCCategoryDecl::anchor() { }
 
+ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
+                                   SourceLocation ClassNameLoc, 
+                                   SourceLocation CategoryNameLoc,
+                                   IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
+                                   ObjCTypeParamList *typeParamList,
+                                   SourceLocation IvarLBraceLoc,
+                                   SourceLocation IvarRBraceLoc)
+  : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
+    ClassInterface(IDecl), TypeParamList(typeParamList),
+    NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc),
+    IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) 
+{
+  // Set the declaration context of each of the type parameters.
+  if (typeParamList) {
+    for (auto typeParam : *typeParamList) {
+      typeParam->setDeclContext(this);
+    }
+  }
+}
+
 ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
                                            SourceLocation AtLoc,
                                            SourceLocation ClassNameLoc,
                                            SourceLocation CategoryNameLoc,
                                            IdentifierInfo *Id,
                                            ObjCInterfaceDecl *IDecl,
+                                           ObjCTypeParamList *typeParamList,
                                            SourceLocation IvarLBraceLoc,
                                            SourceLocation IvarRBraceLoc) {
   ObjCCategoryDecl *CatDecl =
       new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
-                                   IDecl, IvarLBraceLoc, IvarRBraceLoc);
+                                   IDecl, typeParamList, IvarLBraceLoc,
+                                   IvarRBraceLoc);
   if (IDecl) {
     // Link this category into its class's category list.
     CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
@@ -1676,7 +1785,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::Crea
                                                        unsigned ID) {
   return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
                                       SourceLocation(), SourceLocation(),
-                                      nullptr, nullptr);
+                                      nullptr, nullptr, nullptr);
 }
 
 ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {

Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Mon Jul  6 22:57:15 2015
@@ -44,6 +44,8 @@ namespace {
     void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals, 
                              QualType T);
 
+    void PrintObjCTypeParams(ObjCTypeParamList *Params);
+
   public:
     DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
                 unsigned Indentation = 0, bool PrintInstantiation = false)
@@ -962,6 +964,25 @@ void DeclPrinter::PrintObjCMethodType(AS
   Out << ')';
 }
 
+void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) {
+  Out << "<";
+  unsigned First = true;
+  for (auto *Param : *Params) {
+    if (First) {
+      First = false;
+    } else {
+      Out << ", ";
+    }
+
+    Out << Param->getDeclName().getAsString();
+
+    if (Param->hasExplicitBound()) {
+      Out << " : " << Param->getUnderlyingType().getAsString(Policy);
+    }
+  }
+  Out << ">";
+}
+
 void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
   if (OMD->isInstanceMethod())
     Out << "- ";
@@ -1037,14 +1058,24 @@ void DeclPrinter::VisitObjCInterfaceDecl
   ObjCInterfaceDecl *SID = OID->getSuperClass();
 
   if (!OID->isThisDeclarationADefinition()) {
-    Out << "@class " << I << ";";
+    Out << "@class " << I;
+
+    if (auto TypeParams = OID->getTypeParamListAsWritten()) {
+      PrintObjCTypeParams(TypeParams);
+    }
+
+    Out << ";";
     return;
   }
   bool eolnOut = false;
+  Out << "@interface " << I;
+
+  if (auto TypeParams = OID->getTypeParamListAsWritten()) {
+    PrintObjCTypeParams(TypeParams);
+  }
+  
   if (SID)
-    Out << "@interface " << I << " : " << *SID;
-  else
-    Out << "@interface " << I;
+    Out << " : " << OID->getSuperClass()->getName();
 
   // Protocols?
   const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
@@ -1107,7 +1138,11 @@ void DeclPrinter::VisitObjCCategoryImplD
 }
 
 void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
-  Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
+  Out << "@interface " << *PID->getClassInterface();
+  if (auto TypeParams = PID->getTypeParamList()) {
+    PrintObjCTypeParams(TypeParams);
+  }
+  Out << "(" << *PID << ")\n";
   if (PID->ivar_size() > 0) {
     Out << "{\n";
     Indentation += Policy.Indentation;

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Mon Jul  6 22:57:15 2015
@@ -79,6 +79,7 @@ void CodeGenFunction::EmitDecl(const Dec
   case Decl::Captured:
   case Decl::ClassScopeFunctionSpecialization:
   case Decl::UsingShadow:
+  case Decl::ObjCTypeParam:
     llvm_unreachable("Declaration should not be in declstmts!");
   case Decl::Function:  // void X();
   case Decl::Record:    // struct/union/class X;

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Mon Jul  6 22:57:15 2015
@@ -96,14 +96,17 @@ Parser::DeclGroupPtrTy Parser::ParseObjC
 
 ///
 /// objc-class-declaration:
-///    '@' 'class' identifier-list ';'
+///    '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
+///
+/// objc-class-forward-decl:
+///   identifier objc-type-parameter-list[opt]
 ///
 Parser::DeclGroupPtrTy
 Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
   ConsumeToken(); // the identifier "class"
   SmallVector<IdentifierInfo *, 8> ClassNames;
   SmallVector<SourceLocation, 8> ClassLocs;
-
+  SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
 
   while (1) {
     MaybeSkipAttributes(tok::objc_class);
@@ -116,6 +119,14 @@ Parser::ParseObjCAtClassDeclaration(Sour
     ClassLocs.push_back(Tok.getLocation());
     ConsumeToken();
 
+    // Parse the optional objc-type-parameter-list.
+    ObjCTypeParamList *TypeParams = nullptr;
+    if (Tok.is(tok::less)) {
+      TypeParams = parseObjCTypeParamList();
+      if (TypeParams)
+        Actions.popObjCTypeParamList(getCurScope(), TypeParams);
+    }
+    ClassTypeParams.push_back(TypeParams);
     if (!TryConsumeToken(tok::comma))
       break;
   }
@@ -126,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(Sour
 
   return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
                                               ClassLocs.data(),
+                                              ClassTypeParams,
                                               ClassNames.size());
 }
 
@@ -154,15 +166,15 @@ void Parser::CheckNestedObjCContexts(Sou
 ///     objc-category-interface
 ///
 ///   objc-class-interface:
-///     '@' 'interface' identifier objc-superclass[opt]
-///       objc-protocol-refs[opt]
+///     '@' 'interface' identifier objc-type-parameter-list[opt]
+///       objc-superclass[opt] objc-protocol-refs[opt]
 ///       objc-class-instance-variables[opt]
 ///       objc-interface-decl-list
 ///     @end
 ///
 ///   objc-category-interface:
-///     '@' 'interface' identifier '(' identifier[opt] ')'
-///       objc-protocol-refs[opt]
+///     '@' 'interface' identifier objc-type-parameter-list[opt]
+///       '(' identifier[opt] ')' objc-protocol-refs[opt]
 ///       objc-interface-decl-list
 ///     @end
 ///
@@ -202,7 +214,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
   // We have a class or category name - consume it.
   IdentifierInfo *nameId = Tok.getIdentifierInfo();
   SourceLocation nameLoc = ConsumeToken();
-  if (Tok.is(tok::l_paren) && 
+
+  // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
+  // case, LAngleLoc will be valid and ProtocolIdents will capture the
+  // protocol references (that have not yet been resolved).
+  SourceLocation LAngleLoc, EndProtoLoc;
+  SmallVector<IdentifierLocPair, 8> ProtocolIdents;
+  ObjCTypeParamList *typeParameterList = nullptr;
+  if (Tok.is(tok::less)) {
+    typeParameterList = parseObjCTypeParamListOrProtocolRefs(LAngleLoc, 
+                                                             ProtocolIdents,
+                                                             EndProtoLoc);
+  }
+
+  if (Tok.is(tok::l_paren) &&
       !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
     
     BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -237,7 +262,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
     }
     
     // Next, we need to check for any protocol references.
-    SourceLocation LAngleLoc, EndProtoLoc;
+    assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
     SmallVector<Decl *, 8> ProtocolRefs;
     SmallVector<SourceLocation, 8> ProtocolLocs;
     if (Tok.is(tok::less) &&
@@ -248,6 +273,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
     Decl *CategoryType =
     Actions.ActOnStartCategoryInterface(AtLoc,
                                         nameId, nameLoc,
+                                        typeParameterList,
                                         categoryId, categoryLoc,
                                         ProtocolRefs.data(),
                                         ProtocolRefs.size(),
@@ -258,6 +284,10 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
       ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
       
     ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
+
+    if (typeParameterList)
+      Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
+
     return CategoryType;
   }
   // Parse a class interface.
@@ -281,21 +311,44 @@ 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();
   }
+  
   // Next, we need to check for any protocol references.
   SmallVector<Decl *, 8> ProtocolRefs;
   SmallVector<SourceLocation, 8> ProtocolLocs;
-  SourceLocation LAngleLoc, EndProtoLoc;
-  if (Tok.is(tok::less) &&
-      ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
-                                  LAngleLoc, EndProtoLoc))
+  if (LAngleLoc.isValid()) {
+    // We already parsed the protocols named when we thought we had a
+    // type parameter list. Translate them into actual protocol references.
+    for (const auto &pair : ProtocolIdents) {
+      ProtocolLocs.push_back(pair.second);
+    }
+    Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
+                                    /*ForObjCContainer=*/true,
+                                    &ProtocolIdents[0], ProtocolIdents.size(),
+                                    ProtocolRefs);
+  } else if (Tok.is(tok::less) &&
+             ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
+                                         LAngleLoc, EndProtoLoc)) {
     return nullptr;
+  }
 
   if (Tok.isNot(tok::less))
     Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
   
   Decl *ClsType =
-    Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
+    Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList,
                                      superClassId, superClassLoc,
                                      ProtocolRefs.data(), ProtocolRefs.size(),
                                      ProtocolLocs.data(),
@@ -305,6 +358,10 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
     ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
 
   ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
+
+  if (typeParameterList)
+    Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
+
   return ClsType;
 }
 
@@ -339,6 +396,172 @@ static void addContextSensitiveTypeNulla
   }
 }
 
+/// Parse an Objective-C type parameter list, if present, or capture
+/// the locations of the protocol identifiers for a list of protocol
+/// references.
+///
+///   objc-type-parameter-list:
+///     '<' objc-type-parameter (',' objc-type-parameter)* '>'
+///
+///   objc-type-parameter:
+///     identifier objc-type-parameter-bound[opt]
+///
+///   objc-type-parameter-bound:
+///     ':' type-name
+///
+/// \param lAngleLoc The location of the starting '<'.
+///
+/// \param protocolIdents Will capture the list of identifiers, if the
+/// angle brackets contain a list of protocol references rather than a
+/// type parameter list.
+///
+/// \param rAngleLoc The location of the ending '>'.
+ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
+                         SourceLocation &lAngleLoc,
+                         SmallVectorImpl<IdentifierLocPair> &protocolIdents,
+                         SourceLocation &rAngleLoc,
+                         bool mayBeProtocolList) {
+  assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
+
+  // Within the type parameter list, don't treat '>' as an operator.
+  GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+
+  // Local function to "flush" the protocol identifiers, turning them into
+  // type parameters.
+  SmallVector<Decl *, 4> typeParams;
+  auto makeProtocolIdentsIntoTypeParameters = [&]() {
+    for (const auto &pair : protocolIdents) {
+      DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
+                                                        pair.first,
+                                                        pair.second,
+                                                        SourceLocation(),
+                                                        ParsedType());
+      if (typeParam.isUsable())
+        typeParams.push_back(typeParam.get());
+    }
+
+    protocolIdents.clear();
+    mayBeProtocolList = false;
+  };
+
+  bool invalid = false;
+  lAngleLoc = ConsumeToken();
+  do {
+    // Parse the identifier.
+    if (!Tok.is(tok::identifier)) {
+      // Code completion.
+      if (Tok.is(tok::code_completion)) {
+        // FIXME: If these aren't protocol references, we'll need different
+        // completions.
+        Actions.CodeCompleteObjCProtocolReferences(protocolIdents.data(),
+                                                   protocolIdents.size());
+        cutOffParsing();
+
+        // FIXME: Better recovery here?.
+        return nullptr;
+      }
+
+      Diag(Tok, diag::err_objc_expected_type_parameter);
+      invalid = true;
+      break;
+    }
+
+    IdentifierInfo *paramName = Tok.getIdentifierInfo();
+    SourceLocation paramLoc = ConsumeToken();
+
+    // If there is a bound, parse it.
+    SourceLocation colonLoc;
+    TypeResult boundType;
+    if (TryConsumeToken(tok::colon, colonLoc)) {
+      // Once we've seen a bound, we know this is not a list of protocol
+      // references.
+      if (mayBeProtocolList) {
+        // Up until now, we have been queuing up parameters because they
+        // might be protocol references. Turn them into parameters now.
+        makeProtocolIdentsIntoTypeParameters();
+      }
+
+      // type-name
+      boundType = ParseTypeName();
+      if (boundType.isInvalid())
+        invalid = true;
+    } else if (mayBeProtocolList) {
+      // If this could still be a protocol list, just capture the identifier.
+      // We don't want to turn it into a parameter.
+      protocolIdents.push_back(std::make_pair(paramName, paramLoc));
+      continue;
+    }
+
+    // Create the type parameter.
+    DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
+                                                      paramName,
+                                                      paramLoc,
+                                                      colonLoc,
+                                                      boundType.isUsable()
+                                                        ? boundType.get()
+                                                        : ParsedType());
+    if (typeParam.isUsable())
+      typeParams.push_back(typeParam.get());
+  } while (TryConsumeToken(tok::comma));
+
+  // Parse the '>'.
+  if (invalid) {
+    SkipUntil(tok::greater, tok::at, StopBeforeMatch);
+    if (Tok.is(tok::greater))
+      ConsumeToken();
+  } else if (ParseGreaterThanInTemplateList(rAngleLoc,
+                                            /*ConsumeLastToken=*/true,
+                                            /*ObjCGenericList=*/true)) {
+    Diag(lAngleLoc, diag::note_matching) << "'<'";
+    SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
+               tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
+               tok::comma, tok::semi },
+              StopBeforeMatch);
+    if (Tok.is(tok::greater))
+      ConsumeToken();
+  }
+
+  if (mayBeProtocolList) {
+    // A type parameter list must be followed by either a ':' (indicating the
+    // presence of a superclass) or a '(' (indicating that this is a category
+    // or extension). This disambiguates between an objc-type-parameter-list
+    // and a objc-protocol-refs.
+    if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
+      // Returning null indicates that we don't have a type parameter list.
+      // The results the caller needs to handle the protocol references are
+      // captured in the reference parameters already.
+      return nullptr;
+    }
+
+    // We have a type parameter list that looks like a list of protocol
+    // references. Turn that parameter list into type parameters.
+    makeProtocolIdentsIntoTypeParameters();
+  }
+
+  // Form the type parameter list.
+  ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
+                              getCurScope(),
+                              lAngleLoc,
+                              typeParams,
+                              rAngleLoc);
+
+  // Clear out the angle locations; they're used by the caller to indicate
+  // whether there are any protocol references.
+  lAngleLoc = SourceLocation();
+  rAngleLoc = SourceLocation();
+  return list;
+}
+
+/// Parse an objc-type-parameter-list.
+ObjCTypeParamList *Parser::parseObjCTypeParamList() {
+  SourceLocation lAngleLoc;
+  SmallVector<IdentifierLocPair, 1> protocolIdents;
+  SourceLocation rAngleLoc;
+  return parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents, 
+                                              rAngleLoc, 
+                                              /*mayBeProtocolList=*/false);
+}
+
 ///   objc-interface-decl-list:
 ///     empty
 ///     objc-interface-decl-list objc-property-decl [OBJC2]
@@ -1311,7 +1534,8 @@ ParseObjCProtocolReferences(SmallVectorI
   }
 
   // Consume the '>'.
-  if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true))
+  if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true,
+                                     /*ObjCGenericList=*/false))
     return true;
 
   // Convert the list of protocols identifiers into a list of protocol decls.
@@ -1598,6 +1822,22 @@ Parser::ParseObjCAtImplementationDeclara
   SourceLocation nameLoc = ConsumeToken(); // consume class or category name
   Decl *ObjCImpDecl = nullptr;
 
+  // Neither a type parameter list nor a list of protocol references is
+  // permitted here. Parse and diagnose them.
+  if (Tok.is(tok::less)) {
+    SourceLocation lAngleLoc, rAngleLoc;
+    SmallVector<IdentifierLocPair, 8> protocolIdents;
+    SourceLocation diagLoc = Tok.getLocation();
+    if (parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents, 
+                                             rAngleLoc)) {
+      Diag(diagLoc, diag::err_objc_parameterized_implementation)
+        << SourceRange(diagLoc, PrevTokLocation);
+    } else if (lAngleLoc.isValid()) {
+      Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
+        << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
+    }
+  }
+
   if (Tok.is(tok::l_paren)) {
     // we have a category implementation.
     ConsumeParen();

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Jul  6 22:57:15 2015
@@ -738,11 +738,16 @@ void Parser::DiagnoseMisplacedEllipsisIn
 ///
 /// \param RAngleLoc the location of the consumed '>'.
 ///
-/// \param ConsumeLastToken if true, the '>' is not consumed.
+/// \param ConsumeLastToken if true, the '>' is consumed.
+///
+/// \param ObjCGenericList if true, this is the '>' closing an Objective-C
+/// type parameter or type argument list, rather than a C++ template parameter
+/// or argument list.
 ///
 /// \returns true, if current token does not start with '>', false otherwise.
 bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
-                                            bool ConsumeLastToken) {
+                                            bool ConsumeLastToken,
+                                            bool ObjCGenericList) {
   // What will be left once we've consumed the '>'.
   tok::TokenKind RemainingToken;
   const char *ReplacementStr = "> >";
@@ -783,40 +788,44 @@ bool Parser::ParseGreaterThanInTemplateL
   // the token isn't '>>' or '>>>'.
   // '>>>' is for CUDA, where this sequence of characters is parsed into
   // tok::greatergreatergreater, rather than two separate tokens.
-
+  //
+  // We always allow this for Objective-C type parameter and type argument
+  // lists.
   RAngleLoc = Tok.getLocation();
-
-  // The source range of the '>>' or '>=' at the start of the token.
-  CharSourceRange ReplacementRange =
-      CharSourceRange::getCharRange(RAngleLoc,
-          Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(),
-                                         getLangOpts()));
-
-  // A hint to put a space between the '>>'s. In order to make the hint as
-  // clear as possible, we include the characters either side of the space in
-  // the replacement, rather than just inserting a space at SecondCharLoc.
-  FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
-                                                 ReplacementStr);
-
-  // A hint to put another space after the token, if it would otherwise be
-  // lexed differently.
-  FixItHint Hint2;
   Token Next = NextToken();
-  if ((RemainingToken == tok::greater ||
-       RemainingToken == tok::greatergreater) &&
-      Next.isOneOf(tok::greater, tok::greatergreater,
-                   tok::greatergreatergreater, tok::equal, tok::greaterequal,
-                   tok::greatergreaterequal, tok::equalequal) &&
-      areTokensAdjacent(Tok, Next))
-    Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
-
-  unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
-  if (getLangOpts().CPlusPlus11 &&
-      Tok.isOneOf(tok::greatergreater, tok::greatergreatergreater))
-    DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
-  else if (Tok.is(tok::greaterequal))
-    DiagId = diag::err_right_angle_bracket_equal_needs_space;
-  Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2;
+  if (!ObjCGenericList) {
+    // The source range of the '>>' or '>=' at the start of the token.
+    CharSourceRange ReplacementRange =
+        CharSourceRange::getCharRange(RAngleLoc,
+            Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(),
+                                           getLangOpts()));
+
+    // A hint to put a space between the '>>'s. In order to make the hint as
+    // clear as possible, we include the characters either side of the space in
+    // the replacement, rather than just inserting a space at SecondCharLoc.
+    FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
+                                                   ReplacementStr);
+
+    // A hint to put another space after the token, if it would otherwise be
+    // lexed differently.
+    FixItHint Hint2;
+    if ((RemainingToken == tok::greater ||
+         RemainingToken == tok::greatergreater) &&
+        (Next.isOneOf(tok::greater, tok::greatergreater,
+                      tok::greatergreatergreater, tok::equal,
+                      tok::greaterequal, tok::greatergreaterequal,
+                      tok::equalequal)) &&
+        areTokensAdjacent(Tok, Next))
+      Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
+
+    unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
+    if (getLangOpts().CPlusPlus11 &&
+        (Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater)))
+      DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
+    else if (Tok.is(tok::greaterequal))
+      DiagId = diag::err_right_angle_bracket_equal_needs_space;
+    Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2;
+  }
 
   // Strip the initial '>' from the token.
   if (RemainingToken == tok::equal && Next.is(tok::equal) &&
@@ -895,7 +904,8 @@ Parser::ParseTemplateIdAfterTemplateName
     }
   }
 
-  return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken);
+  return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken,
+                                        /*ObjCGenericList=*/false);
 }
 
 /// \brief Replace the tokens that form a simple-template-id with an

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Mon Jul  6 22:57:15 2015
@@ -3029,7 +3029,9 @@ CXCursorKind clang::getCursorKindForDecl
 
       case Decl::Import:
         return CXCursor_ModuleImportDecl;
-      
+
+    case Decl::ObjCTypeParam:   return CXCursor_TemplateTypeParameter;
+
     default:
       if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
         switch (TD->getTagKind()) {

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Jul  6 22:57:15 2015
@@ -20,12 +20,15 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/ExternalSemaSource.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
+#include "TypeLocBuilder.h"
 
 using namespace clang;
 
@@ -461,9 +464,214 @@ static void diagnoseUseOfProtocols(Sema
   }
 }
 
+DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
+                                    SourceLocation paramLoc,
+                                    SourceLocation colonLoc,
+                                    ParsedType parsedTypeBound) {
+  // If there was an explicitly-provided type bound, check it.
+  TypeSourceInfo *typeBoundInfo = nullptr;
+  if (parsedTypeBound) {
+    // The type bound can be any Objective-C pointer type.
+    QualType typeBound = GetTypeFromParser(parsedTypeBound, &typeBoundInfo);
+    if (typeBound->isObjCObjectPointerType()) {
+      // okay
+    } else if (typeBound->isObjCObjectType()) {
+      // The user forgot the * on an Objective-C pointer type, e.g.,
+      // "T : NSView".
+      SourceLocation starLoc = PP.getLocForEndOfToken(
+                                 typeBoundInfo->getTypeLoc().getEndLoc());
+      Diag(typeBoundInfo->getTypeLoc().getBeginLoc(),
+           diag::err_objc_type_param_bound_missing_pointer)
+        << typeBound << paramName
+        << FixItHint::CreateInsertion(starLoc, " *");
+
+      // Create a new type location builder so we can update the type
+      // location information we have.
+      TypeLocBuilder builder;
+      builder.pushFullCopy(typeBoundInfo->getTypeLoc());
+
+      // Create the Objective-C pointer type.
+      typeBound = Context.getObjCObjectPointerType(typeBound);
+      ObjCObjectPointerTypeLoc newT
+        = builder.push<ObjCObjectPointerTypeLoc>(typeBound);
+      newT.setStarLoc(starLoc);
+
+      // Form the new type source information.
+      typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound);
+    } else {
+      // Not a
+      Diag(typeBoundInfo->getTypeLoc().getBeginLoc(),
+           diag::err_objc_type_param_bound_nonobject)
+        << typeBound << paramName;
+
+      // Forget the bound; we'll default to id later.
+      typeBoundInfo = nullptr;
+    }
+  }
+
+  // If there was no explicit type bound (or we removed it due to an error),
+  // use 'id' instead.
+  if (!typeBoundInfo) {
+    colonLoc = SourceLocation();
+    typeBoundInfo = Context.getTrivialTypeSourceInfo(Context.getObjCIdType());
+  }
+
+  // Create the type parameter.
+  return ObjCTypeParamDecl::Create(Context, CurContext, paramLoc, paramName,
+                                   colonLoc, typeBoundInfo);
+}
+
+ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S,
+                                                SourceLocation lAngleLoc,
+                                                ArrayRef<Decl *> typeParamsIn,
+                                                SourceLocation rAngleLoc) {
+  // We know that the array only contains Objective-C type parameters.
+  ArrayRef<ObjCTypeParamDecl *>
+    typeParams(
+      reinterpret_cast<ObjCTypeParamDecl * const *>(typeParamsIn.data()),
+      typeParamsIn.size());
+
+  // Diagnose redeclarations of type parameters.
+  // We do this now because Objective-C type parameters aren't pushed into
+  // scope until later (after the instance variable block), but we want the
+  // diagnostics to occur right after we parse the type parameter list.
+  llvm::SmallDenseMap<IdentifierInfo *, ObjCTypeParamDecl *> knownParams;
+  for (auto typeParam : typeParams) {
+    auto known = knownParams.find(typeParam->getIdentifier());
+    if (known != knownParams.end()) {
+      Diag(typeParam->getLocation(), diag::err_objc_type_param_redecl)
+        << typeParam->getIdentifier()
+        << SourceRange(known->second->getLocation());
+
+      typeParam->setInvalidDecl();
+    } else {
+      knownParams.insert(std::make_pair(typeParam->getIdentifier(), typeParam));
+
+      // Push the type parameter into scope.
+      PushOnScopeChains(typeParam, S, /*AddToContext=*/false);
+    }
+  }
+
+  // Create the parameter list.
+  return ObjCTypeParamList::create(Context, lAngleLoc, typeParams, rAngleLoc);
+}
+
+void Sema::popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList) {
+  for (auto typeParam : *typeParamList) {
+    if (!typeParam->isInvalidDecl()) {
+      S->RemoveDecl(typeParam);
+      IdResolver.RemoveDecl(typeParam);
+    }
+  }
+}
+
+namespace {
+  /// The context in which an Objective-C type parameter list occurs, for use
+  /// in diagnostics.
+  enum class TypeParamListContext {
+    ForwardDeclaration,
+    Definition,
+    Category,
+    Extension
+  };
+}
+
+/// Check consistency between two Objective-C type parameter lists, e.g.,
+/// between a category/extension and an @interface or between an @class and an
+/// @interface.
+static bool checkTypeParamListConsistency(Sema &S,
+                                          ObjCTypeParamList *prevTypeParams,
+                                          ObjCTypeParamList *newTypeParams,
+                                          TypeParamListContext newContext) {
+  // If the sizes don't match, complain about that.
+  if (prevTypeParams->size() != newTypeParams->size()) {
+    SourceLocation diagLoc;
+    if (newTypeParams->size() > prevTypeParams->size()) {
+      diagLoc = newTypeParams->begin()[prevTypeParams->size()]->getLocation();
+    } else {
+      diagLoc = S.PP.getLocForEndOfToken(newTypeParams->back()->getLocEnd());
+    }
+
+    S.Diag(diagLoc, diag::err_objc_type_param_arity_mismatch)
+      << static_cast<unsigned>(newContext)
+      << (newTypeParams->size() > prevTypeParams->size())
+      << prevTypeParams->size()
+      << newTypeParams->size();
+
+    return true;
+  }
+
+  // Match up the type parameters.
+  for (unsigned i = 0, n = prevTypeParams->size(); i != n; ++i) {
+    ObjCTypeParamDecl *prevTypeParam = prevTypeParams->begin()[i];
+    ObjCTypeParamDecl *newTypeParam = newTypeParams->begin()[i];
+
+    // If the bound types match, there's nothing to do.
+    if (S.Context.hasSameType(prevTypeParam->getUnderlyingType(),
+                              newTypeParam->getUnderlyingType()))
+      continue;
+
+    // If the new type parameter's bound was explicit, complain about it being
+    // different from the original.
+    if (newTypeParam->hasExplicitBound()) {
+      SourceRange newBoundRange = newTypeParam->getTypeSourceInfo()
+                                    ->getTypeLoc().getSourceRange();
+      S.Diag(newBoundRange.getBegin(), diag::err_objc_type_param_bound_conflict)
+        << newTypeParam->getUnderlyingType()
+        << newTypeParam->getDeclName()
+        << prevTypeParam->hasExplicitBound()
+        << prevTypeParam->getUnderlyingType()
+        << (newTypeParam->getDeclName() == prevTypeParam->getDeclName())
+        << prevTypeParam->getDeclName()
+        << FixItHint::CreateReplacement(
+             newBoundRange,
+             prevTypeParam->getUnderlyingType().getAsString(
+               S.Context.getPrintingPolicy()));
+
+      S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here)
+        << prevTypeParam->getDeclName();
+
+      // Override the new type parameter's bound type with the previous type,
+      // so that it's consistent.
+      newTypeParam->setTypeSourceInfo(
+        S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType()));
+      continue;
+    }
+
+    // The new type parameter got the implicit bound of 'id'. That's okay for
+    // categories and extensions (overwrite it later), but not for forward
+    // declarations and @interfaces, because those must be standalone.
+    if (newContext == TypeParamListContext::ForwardDeclaration ||
+        newContext == TypeParamListContext::Definition) {
+      // Diagnose this problem for forward declarations and definitions.
+      SourceLocation insertionLoc
+        = S.PP.getLocForEndOfToken(newTypeParam->getLocation());
+      std::string newCode
+        = " : " + prevTypeParam->getUnderlyingType().getAsString(
+                    S.Context.getPrintingPolicy());
+      S.Diag(newTypeParam->getLocation(),
+             diag::err_objc_type_param_bound_missing)
+        << prevTypeParam->getUnderlyingType()
+        << newTypeParam->getDeclName()
+        << (newContext == TypeParamListContext::ForwardDeclaration)
+        << FixItHint::CreateInsertion(insertionLoc, newCode);
+
+      S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here)
+        << prevTypeParam->getDeclName();
+    }
+
+    // Update the new type parameter's bound to match the previous one.
+    newTypeParam->setTypeSourceInfo(
+      S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType()));
+  }
+
+  return false;
+}
+
 Decl *Sema::
 ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
                          IdentifierInfo *ClassName, SourceLocation ClassLoc,
+                         ObjCTypeParamList *typeParamList,
                          IdentifierInfo *SuperName, SourceLocation SuperLoc,
                          Decl * const *ProtoRefs, unsigned NumProtoRefs,
                          const SourceLocation *ProtoLocs, 
@@ -498,10 +706,47 @@ ActOnStartClassInterface(SourceLocation
     ClassName = PrevIDecl->getIdentifier();
   }
 
+  // If there was a forward declaration with type parameters, check
+  // for consistency.
+  if (PrevIDecl) {
+    if (ObjCTypeParamList *prevTypeParamList = PrevIDecl->getTypeParamList()) {
+      if (typeParamList) {
+        // Both have type parameter lists; check for consistency.
+        if (checkTypeParamListConsistency(*this, prevTypeParamList, 
+                                          typeParamList,
+                                          TypeParamListContext::Definition)) {
+          typeParamList = nullptr;
+        }
+      } else {
+        Diag(ClassLoc, diag::err_objc_parameterized_forward_class_first)
+          << ClassName;
+        Diag(prevTypeParamList->getLAngleLoc(), diag::note_previous_decl)
+          << ClassName;
+
+        // Clone the type parameter list.
+        SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams;
+        for (auto typeParam : *prevTypeParamList) {
+          clonedTypeParams.push_back(
+            ObjCTypeParamDecl::Create(
+              Context,
+              CurContext,
+              SourceLocation(),
+              typeParam->getIdentifier(),
+              SourceLocation(),
+              Context.getTrivialTypeSourceInfo(typeParam->getUnderlyingType())));
+        }
+
+        typeParamList = ObjCTypeParamList::create(Context, 
+                                                  SourceLocation(),
+                                                  clonedTypeParams,
+                                                  SourceLocation());
+      }
+    }
+  }
+
   ObjCInterfaceDecl *IDecl
     = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
-                                PrevIDecl, ClassLoc);
-  
+                                typeParamList, PrevIDecl, ClassLoc);
   if (PrevIDecl) {
     // Class already seen. Was it a definition?
     if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
@@ -906,6 +1151,7 @@ Sema::ActOnForwardProtocolDeclaration(So
 Decl *Sema::
 ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
                             IdentifierInfo *ClassName, SourceLocation ClassLoc,
+                            ObjCTypeParamList *typeParamList,
                             IdentifierInfo *CategoryName,
                             SourceLocation CategoryLoc,
                             Decl * const *ProtoRefs,
@@ -925,7 +1171,8 @@ ActOnStartCategoryInterface(SourceLocati
     // the enclosing method declarations.  We mark the decl invalid
     // to make it clear that this isn't a valid AST.
     CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
-                                     ClassLoc, CategoryLoc, CategoryName,IDecl);
+                                     ClassLoc, CategoryLoc, CategoryName,
+                                     IDecl, typeParamList);
     CDecl->setInvalidDecl();
     CurContext->addDecl(CDecl);
         
@@ -951,8 +1198,28 @@ ActOnStartCategoryInterface(SourceLocati
     }
   }
 
+  // If we have a type parameter list, check it.
+  if (typeParamList) {
+    if (auto prevTypeParamList = IDecl->getTypeParamList()) {
+      if (checkTypeParamListConsistency(*this, prevTypeParamList, typeParamList,
+                                        CategoryName
+                                          ? TypeParamListContext::Category
+                                          : TypeParamListContext::Extension))
+        typeParamList = nullptr;
+    } else {
+      Diag(typeParamList->getLAngleLoc(),
+           diag::err_objc_parameterized_category_nonclass)
+        << (CategoryName != nullptr)
+        << ClassName
+        << typeParamList->getSourceRange();
+
+      typeParamList = nullptr;
+    }
+  }
+
   CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
-                                   ClassLoc, CategoryLoc, CategoryName, IDecl);
+                                   ClassLoc, CategoryLoc, CategoryName, IDecl,
+                                   typeParamList);
   // FIXME: PushOnScopeChains?
   CurContext->addDecl(CDecl);
 
@@ -987,7 +1254,8 @@ Decl *Sema::ActOnStartCategoryImplementa
       // Create and install one.
       CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, AtCatImplLoc,
                                           ClassLoc, CatLoc,
-                                          CatName, IDecl);
+                                          CatName, IDecl,
+                                          /*typeParamList=*/nullptr);
       CatIDecl->setImplicit();
     }
   }
@@ -1101,7 +1369,8 @@ Decl *Sema::ActOnStartClassImplementatio
     // FIXME: Do we support attributes on the @implementation? If so we should
     // copy them over.
     IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
-                                      ClassName, /*PrevDecl=*/nullptr, ClassLoc,
+                                      ClassName, /*typeParamList=*/nullptr,
+                                      /*PrevDecl=*/nullptr, ClassLoc,
                                       true);
     IDecl->startDefinition();
     if (SDecl) {
@@ -2083,6 +2352,7 @@ Sema::DeclGroupPtrTy
 Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
                                    IdentifierInfo **IdentList,
                                    SourceLocation *IdentLocs,
+                                   ArrayRef<ObjCTypeParamList *> TypeParamLists,
                                    unsigned NumElts) {
   SmallVector<Decl *, 8> DeclsInGroup;
   for (unsigned i = 0; i != NumElts; ++i) {
@@ -2137,9 +2407,33 @@ Sema::ActOnForwardClassDeclaration(Sourc
       ClassName = PrevIDecl->getIdentifier();
     }
 
+    // If this forward declaration has type parameters, compare them with the
+    // type parameters of the previous declaration.
+    ObjCTypeParamList *TypeParams = TypeParamLists[i];
+    if (PrevIDecl && TypeParams) {
+      if (ObjCTypeParamList *PrevTypeParams = PrevIDecl->getTypeParamList()) {
+        // Check for consistency with the previous declaration.
+        if (checkTypeParamListConsistency(
+              *this, PrevTypeParams, TypeParams,
+              TypeParamListContext::ForwardDeclaration)) {
+          TypeParams = nullptr;
+        }
+      } else if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
+        // The @interface does not have type parameters. Complain.
+        Diag(IdentLocs[i], diag::err_objc_parameterized_forward_class)
+          << ClassName
+          << TypeParams->getSourceRange();
+        Diag(Def->getLocation(), diag::note_defined_here)
+          << ClassName;
+
+        TypeParams = nullptr;
+      }
+    }
+
     ObjCInterfaceDecl *IDecl
       = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
-                                  ClassName, PrevIDecl, IdentLocs[i]);
+                                  ClassName, TypeParams, PrevIDecl,
+                                  IdentLocs[i]);
     IDecl->setAtEndRange(IdentLocs[i]);
     
     PushOnScopeChains(IDecl, TUScope);

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Jul  6 22:57:15 2015
@@ -133,7 +133,7 @@ ExprResult Sema::BuildObjCStringLiteral(
           ObjCInterfaceDecl::Create (Context, 
                                      Context.getTranslationUnitDecl(), 
                                      SourceLocation(), NSIdent, 
-                                     nullptr, SourceLocation());
+                                     nullptr, nullptr, SourceLocation());
         Ty = Context.getObjCInterfaceType(NSStringIDecl);
         Context.setObjCNSStringType(Ty);
       }
@@ -208,7 +208,8 @@ static ObjCMethodDecl *getNSNumberFactor
         S.NSNumberDecl = ObjCInterfaceDecl::Create(CX,
                                                    CX.getTranslationUnitDecl(),
                                                    SourceLocation(), NSNumberId,
-                                                   nullptr, SourceLocation());
+                                                   nullptr, nullptr,
+                                                   SourceLocation());
       } else {
         // Otherwise, require a declaration of NSNumber.
         S.Diag(Loc, diag::err_undeclared_nsnumber);
@@ -475,7 +476,8 @@ ExprResult Sema::BuildObjCBoxedExpr(Sour
             NSStringDecl = ObjCInterfaceDecl::Create(Context, TU,
                                                      SourceLocation(),
                                                      NSStringId,
-                                                     nullptr, SourceLocation());
+                                                     nullptr, nullptr,
+                                                     SourceLocation());
           } else {
             Diag(SR.getBegin(), diag::err_undeclared_nsstring);
             return ExprError();
@@ -591,7 +593,8 @@ ExprResult Sema::BuildObjCBoxedExpr(Sour
           DeclContext *TU = Context.getTranslationUnitDecl();
           NSValueDecl = ObjCInterfaceDecl::Create(Context, TU,
                                                   SourceLocation(), NSValueId,
-                                                  nullptr, SourceLocation());
+                                                  nullptr, nullptr,
+                                                  SourceLocation());
         } else {
           // Otherwise, require a declaration of NSValue.
           Diag(SR.getBegin(), diag::err_undeclared_nsvalue);
@@ -755,7 +758,7 @@ ExprResult Sema::BuildObjCArrayLiteral(S
                             Context.getTranslationUnitDecl(),
                             SourceLocation(),
                             NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
-                            nullptr, SourceLocation());
+                            nullptr, nullptr, SourceLocation());
 
     if (!NSArrayDecl) {
       Diag(SR.getBegin(), diag::err_undeclared_nsarray);
@@ -870,7 +873,7 @@ ExprResult Sema::BuildObjCDictionaryLite
                             Context.getTranslationUnitDecl(),
                             SourceLocation(),
                             NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
-                            nullptr, SourceLocation());
+                            nullptr, nullptr, SourceLocation());
 
     if (!NSDictionaryDecl) {
       Diag(SR.getBegin(), diag::err_undeclared_nsdictionary);

Modified: cfe/trunk/lib/Serialization/ASTCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTCommon.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTCommon.cpp Mon Jul  6 22:57:15 2015
@@ -221,6 +221,7 @@ bool serialization::isRedeclarableDeclKi
   // redeclarable.
   case Decl::ImplicitParam:
   case Decl::ParmVar:
+  case Decl::ObjCTypeParam:
     return false;
   }
 

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Jul  6 22:57:15 2015
@@ -350,8 +350,11 @@ namespace clang {
                               RedeclarableTemplateDecl *Existing,
                               DeclID DsID);
 
+    ObjCTypeParamList *ReadObjCTypeParamList();
+
     // FIXME: Reorder according to DeclNodes.td?
     void VisitObjCMethodDecl(ObjCMethodDecl *D);
+    void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
     void VisitObjCContainerDecl(ObjCContainerDecl *D);
     void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
     void VisitObjCIvarDecl(ObjCIvarDecl *D);
@@ -899,18 +902,46 @@ void ASTDeclReader::VisitObjCMethodDecl(
   MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs);
 }
 
+void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
+  VisitTypedefNameDecl(D);
+  D->ColonLoc = ReadSourceLocation(Record, Idx);
+}
+
 void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
   VisitNamedDecl(CD);
   CD->setAtStartLoc(ReadSourceLocation(Record, Idx));
   CD->setAtEndRange(ReadSourceRange(Record, Idx));
 }
 
+ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() {
+  unsigned numParams = Record[Idx++];
+  if (numParams == 0)
+    return nullptr;
+
+  SmallVector<ObjCTypeParamDecl *, 4> typeParams;
+  typeParams.reserve(numParams);
+  for (unsigned i = 0; i != numParams; ++i) {
+    auto typeParam = ReadDeclAs<ObjCTypeParamDecl>(Record, Idx);
+    if (!typeParam)
+      return nullptr;
+
+    typeParams.push_back(typeParam);
+  }
+
+  SourceLocation lAngleLoc = ReadSourceLocation(Record, Idx);
+  SourceLocation rAngleLoc = ReadSourceLocation(Record, Idx);
+
+  return ObjCTypeParamList::create(Reader.getContext(), lAngleLoc,
+                                   typeParams, rAngleLoc);
+}
+
 void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
   RedeclarableResult Redecl = VisitRedeclarable(ID);
   VisitObjCContainerDecl(ID);
   TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
   mergeRedeclarable(ID, Redecl);
-  
+
+  ID->TypeParamList = ReadObjCTypeParamList();
   if (Record[Idx++]) {
     // Read the definition.
     ID->allocateDefinitionData();
@@ -1020,6 +1051,7 @@ void ASTDeclReader::VisitObjCCategoryDec
   Reader.CategoriesDeserialized.insert(CD);
 
   CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
+  CD->TypeParamList = ReadObjCTypeParamList();
   unsigned NumProtoRefs = Record[Idx++];
   SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
   ProtoRefs.reserve(NumProtoRefs);
@@ -3259,6 +3291,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID I
   case DECL_EMPTY:
     D = EmptyDecl::CreateDeserialized(Context, ID);
     break;
+  case DECL_OBJC_TYPE_PARAM:
+    D = ObjCTypeParamDecl::CreateDeserialized(Context, ID);
+    break;
   }
 
   assert(D && "Unknown declaration reading AST file");

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Mon Jul  6 22:57:15 2015
@@ -117,6 +117,7 @@ namespace clang {
 
     // FIXME: Put in the same order is DeclNodes.td?
     void VisitObjCMethodDecl(ObjCMethodDecl *D);
+    void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
     void VisitObjCContainerDecl(ObjCContainerDecl *D);
     void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
     void VisitObjCIvarDecl(ObjCIvarDecl *D);
@@ -131,6 +132,22 @@ namespace clang {
     void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
     void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
 
+    /// Add an Objective-C type parameter list to the given record.
+    void AddObjCTypeParamList(ObjCTypeParamList *typeParams) {
+      // Empty type parameter list.
+      if (!typeParams) {
+        Record.push_back(0);
+        return;
+      }
+
+      Record.push_back(typeParams->size());
+      for (auto typeParam : *typeParams) {
+        Writer.AddDeclRef(typeParam, Record);
+      }
+      Writer.AddSourceLocation(typeParams->getLAngleLoc(), Record);
+      Writer.AddSourceLocation(typeParams->getRAngleLoc(), Record);
+    }
+
     void AddFunctionDefinition(const FunctionDecl *FD) {
       assert(FD->doesThisDeclarationHaveABody());
       if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
@@ -562,6 +579,13 @@ void ASTDeclWriter::VisitObjCMethodDecl(
   Code = serialization::DECL_OBJC_METHOD;
 }
 
+void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
+  VisitTypedefNameDecl(D);
+  Writer.AddSourceLocation(D->ColonLoc, Record);
+
+  Code = serialization::DECL_OBJC_TYPE_PARAM;
+}
+
 void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
   VisitNamedDecl(D);
   Writer.AddSourceLocation(D->getAtStartLoc(), Record);
@@ -573,6 +597,7 @@ void ASTDeclWriter::VisitObjCInterfaceDe
   VisitRedeclarable(D);
   VisitObjCContainerDecl(D);
   Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
+  AddObjCTypeParamList(D->TypeParamList);
 
   Record.push_back(D->isThisDeclarationADefinition());
   if (D->isThisDeclarationADefinition()) {
@@ -660,6 +685,7 @@ void ASTDeclWriter::VisitObjCCategoryDec
   Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
   Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
   Writer.AddDeclRef(D->getClassInterface(), Record);
+  AddObjCTypeParamList(D->TypeParamList);
   Record.push_back(D->protocol_size());
   for (const auto *I : D->protocols())
     Writer.AddDeclRef(I, Record);

Added: cfe/trunk/test/Index/comment-objc-parameterized-classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/comment-objc-parameterized-classes.m?rev=241541&view=auto
==============================================================================
--- cfe/trunk/test/Index/comment-objc-parameterized-classes.m (added)
+++ cfe/trunk/test/Index/comment-objc-parameterized-classes.m Mon Jul  6 22:57:15 2015
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %s > %t/out
+// RUN: FileCheck %s < %t/out
+
+// Ensure that XML we generate is not invalid.
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out
+// WRONG-NOT: CommentXMLInvalid
+
+ at protocol NSObject
+ at end
+
+ at interface NSObject
+ at end
+
+// CHECK: <Declaration>@interface A <T : id, U : NSObject *> : NSObject
+/// A
+ at interface A<T : id, U : NSObject *> : NSObject
+ at end

Added: cfe/trunk/test/PCH/objc_parameterized_classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_parameterized_classes.m?rev=241541&view=auto
==============================================================================
--- cfe/trunk/test/PCH/objc_parameterized_classes.m (added)
+++ cfe/trunk/test/PCH/objc_parameterized_classes.m Mon Jul  6 22:57:15 2015
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -emit-pch %s -o %t
+// RUN: %clang_cc1 -include-pch %t -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+ at protocol NSObject
+ at end
+
+__attribute__((objc_root_class))
+ at interface NSObject
+ at end
+
+ at interface PC1<T, U : NSObject *> : NSObject
+// expected-note at -2{{type parameter 'U' declared here}}
+ at end
+
+ at interface PC1<T, U : NSObject *> (Cat1)
+ at end
+
+#else
+
+ at interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id}}
+ // expected-note at 15{{type parameter 'T' declared here}}
+               U : id> (Cat2) // expected-error{{type bound 'id' for type parameter 'U' conflicts with previous bound 'NSObject *'}}
+ // expected-note at 15{{type parameter 'U' declared here}}
+ at end
+
+#endif

Modified: cfe/trunk/test/Parser/objc-error-qualified-implementation.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objc-error-qualified-implementation.m?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/test/Parser/objc-error-qualified-implementation.m (original)
+++ cfe/trunk/test/Parser/objc-error-qualified-implementation.m Mon Jul  6 22:57:15 2015
@@ -17,7 +17,7 @@
 
 @interface K @end
 
- at implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}}
+ at implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}} expected-note{{to match this '<'}}
 @end // expected-error {{expected '>'}}
 
 // rdar://13920026

Added: cfe/trunk/test/SemaObjC/parameterized_classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes.m?rev=241541&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/parameterized_classes.m (added)
+++ cfe/trunk/test/SemaObjC/parameterized_classes.m Mon Jul  6 22:57:15 2015
@@ -0,0 +1,192 @@
+// RUN: %clang_cc1 %s -verify
+
+ at protocol NSObject
+ at end
+
+__attribute__((objc_root_class))
+ at interface NSObject <NSObject> // expected-note{{'NSObject' defined here}}
+ at end
+
+ at interface NSString : NSObject
+ at end
+
+// --------------------------------------------------------------------------
+// Parsing parameterized classes.
+// --------------------------------------------------------------------------
+
+// Parse type parameters with a bound
+ at interface PC1<T, U : NSObject*> : NSObject
+// expected-note at -1{{type parameter 'T' declared here}}
+// expected-note at -2{{type parameter 'U' declared here}}
+ at 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 end
+
+// Parse multiple type parameters.
+ at interface PC3<T, U : id> : NSObject
+ at end
+
+// Parse multiple type parameters--grammatically ambiguous with protocol refs.
+ at interface PC4<T, U, V> : NSObject
+ at 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 end
+
+// Parse a type parameter with name conflicts.
+ at interface PC6<T, U, 
+               T> : NSObject // expected-error{{redeclaration of type parameter 'T'}}
+ at end
+
+// Parse Objective-C protocol references.
+ at interface PC7<T> // expected-error{{cannot find protocol declaration for 'T'}}
+ at end
+
+// Parse both type parameters and protocol references.
+ at interface PC8<T> : NSObject <NSObject>
+ at end
+
+// Type parameters with improper bounds.
+ at interface PC9<T : int, // expected-error{{type bound 'int' for type parameter 'T' is not an Objective-C pointer type}}
+               U : NSString> : NSObject // expected-error{{missing '*' in type bound 'NSString' for type parameter 'U'}}
+ at end
+
+// --------------------------------------------------------------------------
+// Parsing parameterized forward declarations classes.
+// --------------------------------------------------------------------------
+
+// Okay: forward declaration without type parameters.
+ at class PC10;
+
+// Okay: forward declarations with type parameters.
+ at class PC10<T, U : NSObject *>, PC11<T : NSObject *, U : id>; // expected-note{{type parameter 'T' declared here}}
+
+// Okay: forward declaration without type parameters following ones
+// with type parameters.
+ at class PC10, PC11;
+
+// Okay: definition of class with type parameters that was formerly
+// declared with the same type parameters.
+ at interface PC10<T, U : NSObject *> : NSObject
+ at end
+
+// Mismatched parameters in declaration of @interface following @class.
+ at interface PC11<T, U> : NSObject // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @interface}}
+ at end
+
+ at interface PC12<T : NSObject *> : NSObject  // expected-note{{type parameter 'T' declared here}}
+ at end
+
+ at class PC12;
+
+// Mismatched parameters in subsequent forward declarations.
+ at class PC13<T : NSObject *>; // expected-note{{type parameter 'T' declared here}}
+ at class PC13;
+ at class PC13<U>; // expected-error{{missing type bound 'NSObject *' for type parameter 'U' in @class}}
+
+// Mismatch parameters in declaration of @class following @interface.
+ at class PC12<T>; // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @class}}
+
+// Parameterized forward declaration a class that is not parameterized.
+ at class NSObject<T>; // expected-error{{forward declaration of non-parameterized class 'NSObject' cannot have type parameters}}
+
+// Parameterized forward declaration preceding the definition (that is
+// not parameterized).
+ at class NSNumber<T : NSObject *>; // expected-note{{'NSNumber' declared here}}
+ at interface NSNumber : NSObject // expected-error{{class 'NSNumber' previously declared with type parameters}}
+ at end
+
+ at class PC14;
+
+// Okay: definition of class with type parameters that was formerly
+// declared without type parameters.
+ at interface PC14<T, U : NSObject *> : NSObject
+ at end
+
+// --------------------------------------------------------------------------
+// Parsing parameterized categories and extensions.
+// --------------------------------------------------------------------------
+
+// Inferring type bounds
+ at interface PC1<T, U> (Cat1) <NSObject>
+ at end
+
+// Matching type bounds
+ at interface PC1<T : id, U : NSObject *> (Cat2) <NSObject>
+ at end
+
+// Inferring type bounds
+ at interface PC1<T, U> () <NSObject>
+ at end
+
+// Matching type bounds
+ at interface PC1<T : id, U : NSObject *> () <NSObject>
+ at end
+
+// Missing type parameters.
+ at interface PC1<T> () // expected-error{{extension has too few type parameters (expected 2, have 1)}}
+ at end
+
+// Extra type parameters.
+ at interface PC1<T, U, V> (Cat3) // expected-error{{category has too many type parameters (expected 2, have 3)}}
+ at end
+
+// Mismatched bounds.
+ at interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id'}}
+               X : id> () // expected-error{{type bound 'id' for type parameter 'X' conflicts with previous bound 'NSObject *'for type parameter 'U'}}
+ at end
+
+// Parameterized category/extension of non-parameterized class.
+ at interface NSObject<T> (Cat1) // expected-error{{category of non-parameterized class 'NSObject' cannot have type parameters}}
+ at end
+
+ at interface NSObject<T> () // expected-error{{extension of non-parameterized class 'NSObject' cannot have type parameters}}
+ at end
+
+// --------------------------------------------------------------------------
+// @implementations cannot have type parameters
+// --------------------------------------------------------------------------
+ at implementation PC1<T : id> // expected-error{{@implementation cannot have type parameters}}
+ at end
+
+ at implementation PC2<T> // expected-error{{@implementation declaration cannot be protocol qualified}}
+ at end
+
+ at implementation PC1<T> (Cat1) // expected-error{{@implementation cannot have type parameters}}
+ at end
+
+ at implementation PC1<T : id> (Cat2) // expected-error{{@implementation cannot have type parameters}}
+ at end
+
+// --------------------------------------------------------------------------
+// Interfaces involving type parameters
+// --------------------------------------------------------------------------
+ at interface PC20<T : id, U : NSObject *, V : NSString *> : NSObject {
+  T object;
+}
+
+- (U)method:(V)param; // expected-note{{passing argument to parameter 'param' here}}
+ at end
+
+ at interface PC20<T, U, V> (Cat1)
+- (U)catMethod:(V)param; // expected-note{{passing argument to parameter 'param' here}}
+ at end
+
+ at interface PC20<X, Y, Z>()
+- (X)extMethod:(Y)param; // expected-note{{passing argument to parameter 'param' here}}
+ at end
+
+void test_PC20_unspecialized(PC20 *pc20) {
+  // FIXME: replace type parameters with underlying types?
+  int *ip = [pc20 method: 0]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'U' (aka 'NSObject *')}}
+  [pc20 method: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
+
+  ip = [pc20 catMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'U' (aka 'NSObject *')}}
+  [pc20 catMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
+
+  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 *')}}
+}

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=241541&r1=241540&r2=241541&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Mon Jul  6 22:57:15 2015
@@ -5038,6 +5038,7 @@ CXCursor clang_getCursorDefinition(CXCur
   case Decl::ClassScopeFunctionSpecialization:
   case Decl::Import:
   case Decl::OMPThreadPrivate:
+  case Decl::ObjCTypeParam:
     return C;
 
   // Declaration kinds that don't make any sense here, but are
@@ -6321,6 +6322,7 @@ static CXLanguageKind getDeclLanguage(co
     case Decl::ObjCProperty:
     case Decl::ObjCPropertyImpl:
     case Decl::ObjCProtocol:
+    case Decl::ObjCTypeParam:
       return CXLanguage_ObjC;
     case Decl::CXXConstructor:
     case Decl::CXXConversion:





More information about the cfe-commits mailing list