r241545 - C++ support for Objective-C lightweight generics.

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


Author: dgregor
Date: Mon Jul  6 22:58:14 2015
New Revision: 241545

URL: http://llvm.org/viewvc/llvm-project?rev=241545&view=rev
Log:
C++ support for Objective-C lightweight generics.

Teach C++'s tentative parsing to handle specializations of Objective-C
class types (e.g., NSArray<NSString *>) as well as Objective-C
protocol qualifiers (id<NSCopying>) by extending type-annotation
tokens to handle this case. As part of this, remove Objective-C
protocol qualifiers from the declaration specifiers, which never
really made sense: instead, provide Sema entry points to make them
part of the type annotation token. Among other things, this properly
diagnoses bogus types such as "<NSCopying> id" which should have been
written as "id <NSCopying>".

Implements template instantiation support for, e.g., NSArray<T>*
in C++. Note that parameterized classes are not templates in the C++
sense, so that cannot (for example) be used as a template argument for
a template template parameter. Part of rdar://problem/6294649.

Added:
    cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm
Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/AST/TypeLoc.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypeLoc.cpp
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseInit.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/DeclSpec.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/Index/annotate-parameterized-classes.m
    cfe/trunk/test/Index/annotate-tokens.m
    cfe/trunk/test/Parser/placeholder-recovery.m
    cfe/trunk/test/SemaObjC/parameterized_classes.m
    cfe/trunk/test/SemaObjC/protocol-archane.m
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/CursorVisitor.h

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Jul  6 22:58:14 2015
@@ -4730,7 +4730,11 @@ class ObjCObjectPointerType : public Typ
   QualType PointeeType;
 
   ObjCObjectPointerType(QualType Canonical, QualType Pointee)
-    : Type(ObjCObjectPointer, Canonical, false, false, false, false),
+    : Type(ObjCObjectPointer, Canonical,
+           Pointee->isDependentType(),
+           Pointee->isInstantiationDependentType(),
+           Pointee->isVariablyModifiedType(),
+           Pointee->containsUnexpandedParameterPack()),
       PointeeType(Pointee) {}
   friend class ASTContext;  // ASTContext creates these.
 

Modified: cfe/trunk/include/clang/AST/TypeLoc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeLoc.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TypeLoc.h (original)
+++ cfe/trunk/include/clang/AST/TypeLoc.h Mon Jul  6 22:58:14 2015
@@ -177,6 +177,9 @@ public:
     memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
   }
 
+  /// Copies the other type loc into this one.
+  void copy(TypeLoc other);
+
   friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
     return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data;
   }
@@ -253,6 +256,10 @@ public:
     // do nothing
   }
 
+  void copyLocal(TypeLoc other) {
+    // do nothing
+  }
+
   TypeLoc getNextTypeLoc() const {
     return getUnqualifiedLoc();
   }
@@ -343,6 +350,20 @@ public:
     return size;
   }
 
+  void copyLocal(Derived other) {
+    // Some subclasses have no data to copy.
+    if (asDerived()->getLocalDataSize() == 0) return;
+
+    // Copy the fixed-sized local data.
+    memcpy(getLocalData(), other.getLocalData(), sizeof(LocalData));
+
+    // Copy the variable-sized local data. We need to do this
+    // separately because the padding in the source and the padding in
+    // the destination might be different.
+    memcpy(getExtraLocalData(), other.getExtraLocalData(),
+           asDerived()->getExtraLocalDataSize());
+  }
+
   TypeLoc getNextTypeLoc() const {
     return getNextTypeLoc(asDerived()->getInnerType());
   }
@@ -892,6 +913,11 @@ public:
     return *(this->getTypePtr()->qual_begin() + i);
   }
 
+
+  ArrayRef<SourceLocation> getProtocolLocs() const {
+    return llvm::makeArrayRef(getProtocolLocArray(), getNumProtocols());
+  }
+
   bool hasBaseTypeAsWritten() const {
     return getLocalData()->HasBaseTypeAsWritten;
   }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul  6 22:58:14 2015
@@ -7817,6 +7817,6 @@ def err_objc_type_arg_not_id_compatible
   "type argument %0 is neither an Objective-C object nor a block type">;
 
 def err_objc_type_arg_does_not_match_bound : Error<
-  "type argument %0 does not satisy the bound (%1) of type parameter %2">;
+  "type argument %0 does not satisfy the bound (%1) of type parameter %2">;
 
 } // end of sema component.

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul  6 22:58:14 2015
@@ -1267,19 +1267,45 @@ private:
                                    bool WarnOnDeclarations,
                                    bool ForObjCContainer,
                                    SourceLocation &LAngleLoc,
-                                   SourceLocation &EndProtoLoc);
-  bool ParseObjCProtocolQualifiers(DeclSpec &DS);
-  void ParseObjCTypeArgsOrProtocolQualifiers(DeclSpec &DS,
-                                             bool warnOnIncompleteProtocols);
+                                   SourceLocation &EndProtoLoc,
+                                   bool consumeLastToken);
+
+  /// Parse the first angle-bracket-delimited clause for an
+  /// Objective-C object or object pointer type, which may be either
+  /// type arguments or protocol qualifiers.
+  void parseObjCTypeArgsOrProtocolQualifiers(
+         SourceLocation &typeArgsLAngleLoc,
+         SmallVectorImpl<ParsedType> &typeArgs,
+         SourceLocation &typeArgsRAngleLoc,
+         SourceLocation &protocolLAngleLoc,
+         SmallVectorImpl<Decl *> &protocols,
+         SmallVectorImpl<SourceLocation> &protocolLocs,
+         SourceLocation &protocolRAngleLoc,
+         bool consumeLastToken,
+         bool warnOnIncompleteProtocols);
 
   /// Parse either Objective-C type arguments or protocol qualifiers; if the
   /// former, also parse protocol qualifiers afterward.
-  void ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS);
+  void parseObjCTypeArgsAndProtocolQualifiers(
+         SourceLocation &typeArgsLAngleLoc,
+         SmallVectorImpl<ParsedType> &typeArgs,
+         SourceLocation &typeArgsRAngleLoc,
+         SourceLocation &protocolLAngleLoc,
+         SmallVectorImpl<Decl *> &protocols,
+         SmallVectorImpl<SourceLocation> &protocolLocs,
+         SourceLocation &protocolRAngleLoc,
+         bool consumeLastToken);
+
+  /// Parse a protocol qualifier type such as '<NSCopying>', which is
+  /// an anachronistic way of writing 'id<NSCopying>'.
+  TypeResult parseObjCProtocolQualifierType(SourceLocation &rAngleLoc);
 
   /// Parse Objective-C type arguments and protocol qualifiers, extending the
   /// current type with the parsed result.
-  TypeResult ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
-                                                    ParsedType type);
+  TypeResult parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
+                                                    ParsedType type,
+                                                    bool consumeLastToken,
+                                                    SourceLocation &endLoc);
 
   void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
                                   Decl *CDecl);

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Jul  6 22:58:14 2015
@@ -373,22 +373,6 @@ private:
   // Scope specifier for the type spec, if applicable.
   CXXScopeSpec TypeScope;
 
-  /// List of Objective-C type arguments, e.g., in \c NSArray<NSView *>.
-  ArrayRef<ParsedType> ObjCTypeArgs;
-
-  /// Location of the '<' that starts a list of Objective-C type arguments.
-  SourceLocation ObjCTypeArgsLAngleLoc;
-  /// Location of the '>' that ends a list of Objective-C type arguments.
-  SourceLocation ObjCTypeArgsRAngleLoc;
-
-  // List of protocol qualifiers for objective-c classes.  Used for
-  // protocol-qualified interfaces "NString<foo>" and protocol-qualified id
-  // "id<foo>".
-  Decl * const *ProtocolQualifiers;
-  unsigned NumProtocolQualifiers;
-  SourceLocation ProtocolLAngleLoc;
-  SourceLocation *ProtocolLocs;
-
   // SourceLocation info.  These are null if the item wasn't specified or if
   // the setting was synthesized.
   SourceRange Range;
@@ -450,17 +434,10 @@ public:
       Constexpr_specified(false),
       Concept_specified(false),
       Attrs(attrFactory),
-      ProtocolQualifiers(nullptr),
-      NumProtocolQualifiers(0),
-      ProtocolLocs(nullptr),
       writtenBS(),
       ObjCQualifiers(nullptr) {
   }
-  ~DeclSpec() {
-    delete [] ObjCTypeArgs.data();
-    delete [] ProtocolQualifiers;
-    delete [] ProtocolLocs;
-  }
+
   // storage-class-specifier
   SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
   TSCS getThreadStorageClassSpec() const {
@@ -499,6 +476,8 @@ public:
   bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; }
   bool isTypeAltiVecBool() const { return TypeAltiVecBool; }
   bool isTypeSpecOwned() const { return TypeSpecOwned; }
+  bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
+
   ParsedType getRepAsType() const {
     assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
     return TypeRep;
@@ -760,38 +739,6 @@ public:
     Attrs.takeAllFrom(attrs);
   }
 
-  /// Determine whether the declaration specifiers contain Objective-C
-  /// type arguments.
-  bool hasObjCTypeArgs() const { return !ObjCTypeArgs.empty(); }
-
-  ArrayRef<ParsedType> getObjCTypeArgs() const { return ObjCTypeArgs; }
-  SourceLocation getObjCTypeArgsLAngleLoc() const {
-    return ObjCTypeArgsLAngleLoc;
-  }
-  SourceLocation getObjCTypeArgsRAngleLoc() const {
-    return ObjCTypeArgsRAngleLoc;
-  }
-  SourceRange getObjCTypeArgsRange() const {
-    return SourceRange(ObjCTypeArgsLAngleLoc, ObjCTypeArgsRAngleLoc);
-  }
-
-  void setObjCTypeArgs(SourceLocation lAngleLoc,
-                       ArrayRef<ParsedType> args,
-                       SourceLocation rAngleLoc);
-
-  typedef Decl * const *ProtocolQualifierListTy;
-  ProtocolQualifierListTy getProtocolQualifiers() const {
-    return ProtocolQualifiers;
-  }
-  SourceLocation *getProtocolLocs() const { return ProtocolLocs; }
-  unsigned getNumProtocolQualifiers() const {
-    return NumProtocolQualifiers;
-  }
-  SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; }
-  void setProtocolQualifiers(Decl * const *Protos, unsigned NP,
-                             SourceLocation *ProtoLocs,
-                             SourceLocation LAngleLoc);
-
   /// Finish - This does final analysis of the declspec, issuing diagnostics for
   /// things like "_Imaginary" (lacking an FP type).  After calling this method,
   /// DeclSpec is guaranteed self-consistent, even if an error occurred.

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul  6 22:58:14 2015
@@ -7191,17 +7191,54 @@ public:
 
   /// Given a list of identifiers (and their locations), resolve the
   /// names to either Objective-C protocol qualifiers or type
-  /// arguments, as appropriate. The result will be attached to the
-  /// given declaration specifiers.
+  /// arguments, as appropriate.
   void actOnObjCTypeArgsOrProtocolQualifiers(
          Scope *S,
-         DeclSpec &DS,
          SourceLocation lAngleLoc,
          ArrayRef<IdentifierInfo *> identifiers,
          ArrayRef<SourceLocation> identifierLocs,
          SourceLocation rAngleLoc,
+         SourceLocation &typeArgsLAngleLoc,
+         SmallVectorImpl<ParsedType> &typeArgs,
+         SourceLocation &typeArgsRAngleLoc,
+         SourceLocation &protocolLAngleLoc,
+         SmallVectorImpl<Decl *> &protocols,
+         SourceLocation &protocolRAngleLoc,
          bool warnOnIncompleteProtocols);
 
+  /// Build a an Objective-C protocol-qualified 'id' type where no
+  /// base type was specified.
+  TypeResult actOnObjCProtocolQualifierType(
+               SourceLocation lAngleLoc,
+               ArrayRef<Decl *> protocols,
+               ArrayRef<SourceLocation> protocolLocs,
+               SourceLocation rAngleLoc);
+
+  /// Build a specialized and/or protocol-qualified Objective-C type.
+  TypeResult actOnObjCTypeArgsAndProtocolQualifiers(
+               Scope *S,
+               SourceLocation Loc,
+               ParsedType BaseType,
+               SourceLocation TypeArgsLAngleLoc,
+               ArrayRef<ParsedType> TypeArgs,
+               SourceLocation TypeArgsRAngleLoc,
+               SourceLocation ProtocolLAngleLoc,
+               ArrayRef<Decl *> Protocols,
+               ArrayRef<SourceLocation> ProtocolLocs,
+               SourceLocation ProtocolRAngleLoc);
+
+  /// Build an Objective-C object pointer type.
+  QualType BuildObjCObjectType(QualType BaseType,
+                               SourceLocation Loc,
+                               SourceLocation TypeArgsLAngleLoc,
+                               ArrayRef<TypeSourceInfo *> TypeArgs,
+                               SourceLocation TypeArgsRAngleLoc,
+                               SourceLocation ProtocolLAngleLoc,
+                               ArrayRef<ObjCProtocolDecl *> Protocols,
+                               ArrayRef<SourceLocation> ProtocolLocs,
+                               SourceLocation ProtocolRAngleLoc,
+                               bool FailOnError = false);
+
   /// Ensure attributes are consistent with type.
   /// \param [in, out] Attributes The attributes to check; they will
   /// be modified to be consistent with \p PropertyTy.

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Jul  6 22:58:14 2015
@@ -469,7 +469,10 @@ const RecordType *Type::getAsUnionType()
 ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
                                ArrayRef<QualType> typeArgs,
                                ArrayRef<ObjCProtocolDecl *> protocols)
-  : Type(ObjCObject, Canonical, false, false, false, false),
+  : Type(ObjCObject, Canonical, Base->isDependentType(), 
+         Base->isInstantiationDependentType(), 
+         Base->isVariablyModifiedType(), 
+         Base->containsUnexpandedParameterPack()),
     BaseType(Base) 
 {
   ObjCObjectTypeBits.NumTypeArgs = typeArgs.size();
@@ -484,6 +487,16 @@ ObjCObjectType::ObjCObjectType(QualType
   if (!protocols.empty())
     memcpy(getProtocolStorage(), protocols.data(),
            protocols.size() * sizeof(ObjCProtocolDecl*));
+
+  for (auto typeArg : typeArgs) {
+    if (typeArg->isDependentType())
+      setDependent();
+    else if (typeArg->isInstantiationDependentType())
+      setInstantiationDependent();
+
+    if (typeArg->containsUnexpandedParameterPack())
+      setContainsUnexpandedParameterPack();
+  }
 }
 
 bool ObjCObjectType::isSpecialized() const { 

Modified: cfe/trunk/lib/AST/TypeLoc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeLoc.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypeLoc.cpp (original)
+++ cfe/trunk/lib/AST/TypeLoc.cpp Mon Jul  6 22:58:14 2015
@@ -19,6 +19,8 @@
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
+static const unsigned TypeLocMaxDataAlign = llvm::alignOf<void *>();
+
 //===----------------------------------------------------------------------===//
 // TypeLoc Implementation
 //===----------------------------------------------------------------------===//
@@ -125,6 +127,46 @@ void TypeLoc::initializeImpl(ASTContext
   }
 }
 
+namespace {
+  class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> {
+    TypeLoc Source;
+  public:
+    TypeLocCopier(TypeLoc source) : Source(source) { }
+
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT)                          \
+    void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) {   \
+      dest.copyLocal(Source.castAs<CLASS##TypeLoc>());  \
+    }
+#include "clang/AST/TypeLocNodes.def"
+  };
+}
+
+
+void TypeLoc::copy(TypeLoc other) {
+  assert(getFullDataSize() == other.getFullDataSize());
+
+  // If both data pointers are aligned to the maximum alignment, we
+  // can memcpy because getFullDataSize() accurately reflects the
+  // layout of the data.
+  if (reinterpret_cast<uintptr_t>(Data)
+        == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(Data),
+                                    TypeLocMaxDataAlign) &&
+      reinterpret_cast<uintptr_t>(other.Data)
+        == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(other.Data),
+                                    TypeLocMaxDataAlign)) {
+    memcpy(Data, other.Data, getFullDataSize());
+    return;
+  }
+
+  // Copy each of the pieces.
+  TypeLoc TL(getType(), Data);
+  do {
+    TypeLocCopier(other).Visit(TL);
+    other = other.getNextTypeLoc();
+  } while ((TL = TL.getNextTypeLoc()));
+}
+
 SourceLocation TypeLoc::getBeginLoc() const {
   TypeLoc Cur = *this;
   TypeLoc LeftMost = Cur;

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Mon Jul  6 22:58:14 2015
@@ -1106,6 +1106,7 @@ static bool HasFeature(const Preprocesso
       .Case("arc_cf_code_audited", true)
       .Case("objc_bridge_id", true)
       .Case("objc_bridge_id_on_typedefs", true)
+      .Case("objc_generics", LangOpts.ObjC2)
       // C11 features
       .Case("c_alignas", LangOpts.C11)
       .Case("c_alignof", LangOpts.C11)

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul  6 22:58:14 2015
@@ -2144,8 +2144,7 @@ void Parser::ParseSpecifierQualifierList
   if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) {
     Diag(Tok, diag::err_expected_type);
     DS.SetTypeSpecError();
-  } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
-             !DS.hasAttributes()) {
+  } else if (Specs == DeclSpec::PQ_None && !DS.hasAttributes()) {
     Diag(Tok, diag::err_typename_requires_specqual);
     if (!DS.hasTypeSpecifier())
       DS.SetTypeSpecError();
@@ -2886,13 +2885,6 @@ void Parser::ParseDeclarationSpecifiers(
       DS.SetRangeEnd(Tok.getAnnotationEndLoc());
       ConsumeToken(); // The typename
 
-      // Objective-C supports type arguments and protocol references
-      // following an Objective-C object pointer type. Handle either
-      // one of them.
-      if (Tok.is(tok::less) && getLangOpts().ObjC1) {
-        ParseObjCTypeArgsAndProtocolQualifiers(DS);
-      }
-
       continue;
     }
 
@@ -2999,10 +2991,17 @@ void Parser::ParseDeclarationSpecifiers(
       ConsumeToken(); // The identifier
 
       // Objective-C supports type arguments and protocol references
-      // following an Objective-C object pointer type. Handle either
-      // one of them.
+      // following an Objective-C object or object pointer
+      // type. Handle either one of them.
       if (Tok.is(tok::less) && getLangOpts().ObjC1) {
-        ParseObjCTypeArgsAndProtocolQualifiers(DS);
+        SourceLocation NewEndLoc;
+        TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers(
+                                  Loc, TypeRep, /*consumeLastToken=*/true,
+                                  NewEndLoc);
+        if (NewTypeRep.isUsable()) {
+          DS.UpdateTypeRep(NewTypeRep.get());
+          DS.SetRangeEnd(NewEndLoc);
+        }
       }
 
       // Need to support trailing type qualifiers (e.g. "id<p> const").
@@ -3420,10 +3419,19 @@ void Parser::ParseDeclarationSpecifiers(
       if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1)
         goto DoneWithDeclSpec;
 
-      if (!ParseObjCProtocolQualifiers(DS))
-        Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
-          << FixItHint::CreateInsertion(Loc, "id")
-          << SourceRange(Loc, DS.getSourceRange().getEnd());
+      SourceLocation StartLoc = Tok.getLocation();
+      SourceLocation EndLoc;
+      TypeResult Type = parseObjCProtocolQualifierType(EndLoc);
+      if (Type.isUsable()) {
+        if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, StartLoc,
+                               PrevSpec, DiagID, Type.get(),
+                               Actions.getASTContext().getPrintingPolicy()))
+          Diag(StartLoc, DiagID) << PrevSpec;
+        
+        DS.SetRangeEnd(EndLoc);
+      } else {
+        DS.SetTypeSpecError();
+      }
 
       // Need to support trailing type qualifiers (e.g. "id<p> const").
       // If a type specifier follows, it will be diagnosed elsewhere.

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Jul  6 22:58:14 2015
@@ -1805,13 +1805,6 @@ void Parser::ParseCXXSimpleTypeSpecifier
     DS.SetRangeEnd(Tok.getAnnotationEndLoc());
     ConsumeToken();
     
-    // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
-    // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
-    // Objective-C interface.  If we don't have Objective-C or a '<', this is
-    // just a normal reference to a typedef name.
-    if (Tok.is(tok::less) && getLangOpts().ObjC1)
-      ParseObjCProtocolQualifiers(DS);
-    
     DS.Finish(Diags, PP, Policy);
     return;
   }

Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Mon Jul  6 22:58:14 2015
@@ -274,8 +274,11 @@ ExprResult Parser::ParseInitializerWithP
 
         // Parse type arguments and protocol qualifiers.
         if (Tok.is(tok::less)) {
+          SourceLocation NewEndLoc;
           TypeResult NewReceiverType
-            = ParseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType);
+            = parseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType,
+                                                     /*consumeLastToken=*/true,
+                                                     NewEndLoc);
           if (!NewReceiverType.isUsable()) {
             SkipUntil(tok::r_square, StopAtSemi);
             return ExprError();

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Mon Jul  6 22:58:14 2015
@@ -267,7 +267,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
     SmallVector<SourceLocation, 8> ProtocolLocs;
     if (Tok.is(tok::less) &&
         ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
-                                    LAngleLoc, EndProtoLoc))
+                                    LAngleLoc, EndProtoLoc,
+                                    /*consumeLastToken=*/true))
       return nullptr;
 
     Decl *CategoryType =
@@ -293,8 +294,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
   // Parse a class interface.
   IdentifierInfo *superClassId = nullptr;
   SourceLocation superClassLoc;
-  DeclSpec superClassDS(AttrFactory);
-
+  SourceLocation typeArgsLAngleLoc;
+  SmallVector<ParsedType, 4> typeArgs;
+  SourceLocation typeArgsRAngleLoc;
+  SmallVector<Decl *, 4> protocols;
+  SmallVector<SourceLocation, 4> protocolLocs;
   if (Tok.is(tok::colon)) { // a super class is specified.
     ConsumeToken();
 
@@ -315,51 +319,50 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
 
     // Type arguments for the superclass or protocol conformances.
     if (Tok.is(tok::less)) {
-      ParseObjCTypeArgsOrProtocolQualifiers(superClassDS,
+      parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
+                                            typeArgs,
+                                            typeArgsRAngleLoc,
+                                            LAngleLoc,
+                                            protocols,
+                                            protocolLocs,
+                                            EndProtoLoc,
+                                            /*consumeLastToken=*/true,
                                             /*warnOnIncompleteProtocols=*/true);
     }
   }
   
   // Next, we need to check for any protocol references.
-  SmallVector<Decl *, 8> ProtocolRefs;
-  SmallVector<SourceLocation, 8> ProtocolLocs;
   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 (auto protocols = superClassDS.getProtocolQualifiers()) {
-    // We already parsed the protocols named when we thought we had a
-    // type argument list (for a specialized superclass). Treat them
-    // as actual protocol references.
-    unsigned numProtocols = superClassDS.getNumProtocolQualifiers();
-    ProtocolRefs.append(protocols, protocols + numProtocols);
-    ProtocolLocs.append(superClassDS.getProtocolLocs(),
-                        superClassDS.getProtocolLocs() + numProtocols);
-    LAngleLoc = superClassDS.getProtocolLAngleLoc();
-    EndProtoLoc = superClassDS.getLocEnd();
-  } else if (Tok.is(tok::less) &&
-             ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
-                                         LAngleLoc, EndProtoLoc)) {
+    if (!ProtocolIdents.empty()) {
+      // 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(),
+                                      protocols);
+    }
+  } else if (protocols.empty() && Tok.is(tok::less) &&
+             ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
+                                         LAngleLoc, EndProtoLoc,
+                                         /*consumeLastToken=*/true)) {
     return nullptr;
   }
 
   if (Tok.isNot(tok::less))
-    Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
+    Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc);
   
   Decl *ClsType =
     Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, 
                                      typeParameterList, superClassId, 
                                      superClassLoc, 
-                                     superClassDS.getObjCTypeArgs(),
-                                     superClassDS.getObjCTypeArgsRange(),
-                                     ProtocolRefs.data(), ProtocolRefs.size(),
-                                     ProtocolLocs.data(),
+                                     typeArgs,
+                                     SourceRange(typeArgsLAngleLoc,
+                                                 typeArgsRAngleLoc),
+                                     protocols.data(), protocols.size(),
+                                     protocolLocs.data(),
                                      EndProtoLoc, attrs.getList());
 
   if (Tok.is(tok::l_brace))
@@ -1515,7 +1518,8 @@ bool Parser::
 ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
                             SmallVectorImpl<SourceLocation> &ProtocolLocs,
                             bool WarnOnDeclarations, bool ForObjCContainer,
-                            SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
+                            SourceLocation &LAngleLoc, SourceLocation &EndLoc,
+                            bool consumeLastToken) {
   assert(Tok.is(tok::less) && "expected <");
 
   LAngleLoc = ConsumeToken(); // the "<"
@@ -1545,7 +1549,7 @@ ParseObjCProtocolReferences(SmallVectorI
   }
 
   // Consume the '>'.
-  if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true,
+  if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken,
                                      /*ObjCGenericList=*/false))
     return true;
 
@@ -1556,30 +1560,43 @@ ParseObjCProtocolReferences(SmallVectorI
   return false;
 }
 
-/// \brief Parse the Objective-C protocol qualifiers that follow a typename
-/// in a decl-specifier-seq, starting at the '<'.
-bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
+TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
   assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
   assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C");
-  SourceLocation LAngleLoc, EndProtoLoc;
-  SmallVector<Decl *, 8> ProtocolDecl;
-  SmallVector<SourceLocation, 8> ProtocolLocs;
-  bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
-                                            false, LAngleLoc, EndProtoLoc);
-  DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
-                           ProtocolLocs.data(), LAngleLoc);
-  if (EndProtoLoc.isValid())
-    DS.SetRangeEnd(EndProtoLoc);
-  return Result;
+
+  SourceLocation lAngleLoc;
+  SmallVector<Decl *, 8> protocols;
+  SmallVector<SourceLocation, 8> protocolLocs;
+  (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
+                                    lAngleLoc, rAngleLoc,
+                                    /*consumeLastToken=*/true);
+  TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
+                                                             protocols,
+                                                             protocolLocs,
+                                                             rAngleLoc);
+  if (result.isUsable()) {
+    Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
+      << FixItHint::CreateInsertion(lAngleLoc, "id")
+      << SourceRange(lAngleLoc, rAngleLoc);
+  }
+
+  return result;
 }
 
 /// Parse Objective-C type arguments or protocol qualifiers.
 ///
 ///   objc-type-arguments:
-///     '<' type-name (',' type-name)* '>'
+///     '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
 ///
-void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
-       DeclSpec &DS,
+void Parser::parseObjCTypeArgsOrProtocolQualifiers(
+       SourceLocation &typeArgsLAngleLoc,
+       SmallVectorImpl<ParsedType> &typeArgs,
+       SourceLocation &typeArgsRAngleLoc,
+       SourceLocation &protocolLAngleLoc,
+       SmallVectorImpl<Decl *> &protocols,
+       SmallVectorImpl<SourceLocation> &protocolLocs,
+       SourceLocation &protocolRAngleLoc,
+       bool consumeLastToken,
        bool warnOnIncompleteProtocols) {
   assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
   SourceLocation lAngleLoc = ConsumeToken();
@@ -1588,7 +1605,7 @@ void Parser::ParseObjCTypeArgsOrProtocol
   // identifiers, which might be types or might be protocols.
   bool allSingleIdentifiers = true;
   SmallVector<IdentifierInfo *, 4> identifiers;
-  SmallVector<SourceLocation, 4> identifierLocs;
+  SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
 
   // Parse a list of comma-separated identifiers, bailing out if we
   // see something different.
@@ -1626,23 +1643,27 @@ void Parser::ParseObjCTypeArgsOrProtocol
   if (allSingleIdentifiers) {
     // Parse the closing '>'.
     SourceLocation rAngleLoc;
-    (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+    (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
                                          /*ObjCGenericList=*/true);
 
     // Let Sema figure out what we parsed.
     Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
-                                                  DS,
                                                   lAngleLoc,
                                                   identifiers,
                                                   identifierLocs,
                                                   rAngleLoc,
+                                                  typeArgsLAngleLoc,
+                                                  typeArgs,
+                                                  typeArgsRAngleLoc,
+                                                  protocolLAngleLoc,
+                                                  protocols,
+                                                  protocolRAngleLoc,
                                                   warnOnIncompleteProtocols);
     return;
   }
 
   // We syntactically matched a type argument, so commit to parsing
   // type arguments.
-  SmallVector<ParsedType, 4> typeArgs;
 
   // Convert the identifiers into type arguments.
   bool invalid = false;
@@ -1650,7 +1671,19 @@ void Parser::ParseObjCTypeArgsOrProtocol
     ParsedType typeArg
       = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
     if (typeArg) {
-      typeArgs.push_back(typeArg);
+      DeclSpec DS(AttrFactory);
+      const char *prevSpec = nullptr;
+      unsigned diagID;
+      DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
+                         typeArg, Actions.getASTContext().getPrintingPolicy());
+
+      // Form a declarator to turn this into a type.
+      Declarator D(DS, Declarator::TypeNameContext);
+      TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
+      if (fullTypeArg.isUsable())
+        typeArgs.push_back(fullTypeArg.get());
+      else
+        invalid = true;
     } else {
       invalid = true;
     }
@@ -1659,6 +1692,14 @@ void Parser::ParseObjCTypeArgsOrProtocol
   // Continue parsing type-names.
   do {
     TypeResult typeArg = ParseTypeName();
+
+    // Consume the '...' for a pack expansion.
+    SourceLocation ellipsisLoc;
+    TryConsumeToken(tok::ellipsis, ellipsisLoc);
+    if (typeArg.isUsable() && ellipsisLoc.isValid()) {
+      typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
+    }
+
     if (typeArg.isUsable()) {
       typeArgs.push_back(typeArg.get());
     } else {
@@ -1668,53 +1709,105 @@ void Parser::ParseObjCTypeArgsOrProtocol
 
   // Parse the closing '>'.
   SourceLocation rAngleLoc;
-  (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+  (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
                                        /*ObjCGenericList=*/true);
 
-  if (invalid)
+  if (invalid) {
+    typeArgs.clear();
     return;
+  }
 
-  // Update the DeclSpec appropriately.
-  DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+  // Record left/right angle locations.
+  typeArgsLAngleLoc = lAngleLoc;
+  typeArgsRAngleLoc = rAngleLoc;
 }
 
-void Parser::ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS) {
+void Parser::parseObjCTypeArgsAndProtocolQualifiers(
+       SourceLocation &typeArgsLAngleLoc,
+       SmallVectorImpl<ParsedType> &typeArgs,
+       SourceLocation &typeArgsRAngleLoc,
+       SourceLocation &protocolLAngleLoc,
+       SmallVectorImpl<Decl *> &protocols,
+       SmallVectorImpl<SourceLocation> &protocolLocs,
+       SourceLocation &protocolRAngleLoc,
+       bool consumeLastToken) {
   assert(Tok.is(tok::less));
 
-  ParseObjCTypeArgsOrProtocolQualifiers(DS,
+  // Parse the first angle-bracket-delimited clause.
+  parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
+                                        typeArgs,
+                                        typeArgsRAngleLoc,
+                                        protocolLAngleLoc,
+                                        protocols,
+                                        protocolLocs,
+                                        protocolRAngleLoc,
+                                        consumeLastToken,
                                         /*warnOnIncompleteProtocols=*/false);
 
   // An Objective-C object pointer followed by type arguments
   // can then be followed again by a set of protocol references, e.g.,
   // \c NSArray<NSView><NSTextDelegate>
-  if (Tok.is(tok::less)) {
-    if (DS.getProtocolQualifiers()) {
+  if ((consumeLastToken && Tok.is(tok::less)) ||
+      (!consumeLastToken && NextToken().is(tok::less))) {
+    // If we aren't consuming the last token, the prior '>' is still hanging
+    // there. Consume it before we parse the protocol qualifiers.
+    if (!consumeLastToken)
+      ConsumeToken();
+
+    if (!protocols.empty()) {
+      SkipUntilFlags skipFlags = SkipUntilFlags();
+      if (!consumeLastToken)
+        skipFlags = skipFlags | StopBeforeMatch;
       Diag(Tok, diag::err_objc_type_args_after_protocols)
-        << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
-      SkipUntil(tok::greater, tok::greatergreater);
+        << SourceRange(protocolLAngleLoc, protocolRAngleLoc);
+      SkipUntil(tok::greater, tok::greatergreater, skipFlags);
     } else {
-      ParseObjCProtocolQualifiers(DS);
+      ParseObjCProtocolReferences(protocols, protocolLocs, 
+                                  /*WarnOnDeclarations=*/false,
+                                  /*ForObjCContainer=*/false,
+                                  protocolLAngleLoc, protocolRAngleLoc, 
+                                  consumeLastToken);
     }
   }
 }
 
-TypeResult Parser::ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
-                                                          ParsedType type) {
+TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
+             SourceLocation loc,
+             ParsedType type,
+             bool consumeLastToken,
+             SourceLocation &endLoc) {
   assert(Tok.is(tok::less));
-
-  // Create declaration specifiers and set the type as the type specifier.
-  DeclSpec DS(AttrFactory);
-  const char *prevSpec = nullptr;
-  unsigned diagID;
-  DS.SetTypeSpecType(TST_typename, loc, prevSpec, diagID, type,
-                     Actions.getASTContext().getPrintingPolicy());
+  SourceLocation typeArgsLAngleLoc;
+  SmallVector<ParsedType, 4> typeArgs;
+  SourceLocation typeArgsRAngleLoc;
+  SourceLocation protocolLAngleLoc;
+  SmallVector<Decl *, 4> protocols;
+  SmallVector<SourceLocation, 4> protocolLocs;
+  SourceLocation protocolRAngleLoc;
 
   // Parse type arguments and protocol qualifiers.
-  ParseObjCTypeArgsAndProtocolQualifiers(DS);
+  parseObjCTypeArgsAndProtocolQualifiers(typeArgsLAngleLoc, typeArgs,
+                                         typeArgsRAngleLoc, protocolLAngleLoc,
+                                         protocols, protocolLocs,
+                                         protocolRAngleLoc, consumeLastToken);
+
+  // Compute the location of the last token.
+  if (consumeLastToken)
+    endLoc = PrevTokLocation;
+  else
+    endLoc = Tok.getLocation();
 
-  // Form a declarator to turn this into a type.
-  Declarator D(DS, Declarator::TypeNameContext);
-  return Actions.ActOnTypeName(getCurScope(), D);
+  return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
+           getCurScope(),
+           loc,
+           type,
+           typeArgsLAngleLoc,
+           typeArgs,
+           typeArgsRAngleLoc,
+           protocolLAngleLoc,
+           protocols,
+           protocolLocs,
+           protocolRAngleLoc);
 }
 
 void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
@@ -1926,7 +2019,8 @@ Parser::ParseObjCAtProtocolDeclaration(S
   SmallVector<SourceLocation, 8> ProtocolLocs;
   if (Tok.is(tok::less) &&
       ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
-                                  LAngleLoc, EndProtoLoc))
+                                  LAngleLoc, EndProtoLoc,
+                                  /*consumeLastToken=*/true))
     return DeclGroupPtrTy();
 
   Decl *ProtoType =
@@ -2020,9 +2114,14 @@ Parser::ParseObjCAtImplementationDeclara
     rparenLoc = ConsumeParen();
     if (Tok.is(tok::less)) { // we have illegal '<' try to recover
       Diag(Tok, diag::err_unexpected_protocol_qualifier);
-      AttributeFactory attr;
-      DeclSpec DS(attr);
-      (void)ParseObjCProtocolQualifiers(DS);
+      SourceLocation protocolLAngleLoc, protocolRAngleLoc;
+      SmallVector<Decl *, 4> protocols;
+      SmallVector<SourceLocation, 4> protocolLocs;
+      (void)ParseObjCProtocolReferences(protocols, protocolLocs, 
+                                        /*warnOnIncompleteProtocols=*/false,
+                                        /*ForObjCContainer=*/false,
+                                        protocolLAngleLoc, protocolRAngleLoc,
+                                        /*consumeLastToken=*/true);
     }
     ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
                                     AtLoc, nameId, nameLoc, categoryId,
@@ -2050,10 +2149,15 @@ Parser::ParseObjCAtImplementationDeclara
       ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
     else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
       Diag(Tok, diag::err_unexpected_protocol_qualifier);
-      // try to recover.
-      AttributeFactory attr;
-      DeclSpec DS(attr);
-      (void)ParseObjCProtocolQualifiers(DS);
+
+      SourceLocation protocolLAngleLoc, protocolRAngleLoc;
+      SmallVector<Decl *, 4> protocols;
+      SmallVector<SourceLocation, 4> protocolLocs;
+      (void)ParseObjCProtocolReferences(protocols, protocolLocs, 
+                                        /*warnOnIncompleteProtocols=*/false,
+                                        /*ForObjCContainer=*/false,
+                                        protocolLAngleLoc, protocolRAngleLoc,
+                                        /*consumeLastToken=*/true);
     }
   }
   assert(ObjCImpDecl);
@@ -2873,8 +2977,11 @@ ExprResult Parser::ParseObjCMessageExpre
 
       // Parse type arguments and protocol qualifiers.
       if (Tok.is(tok::less)) {
+        SourceLocation NewEndLoc;
         TypeResult NewReceiverType
-          = ParseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType);
+          = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
+                                                   /*consumeLastToken=*/true,
+                                                   NewEndLoc);
         if (!NewReceiverType.isUsable()) {
           SkipUntil(tok::r_square, StopAtSemi);
           return ExprError();

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Jul  6 22:58:14 2015
@@ -1413,14 +1413,35 @@ Parser::TryAnnotateName(bool IsAddressOf
     // It's not something we know about. Leave it unannotated.
     break;
 
-  case Sema::NC_Type:
-    Tok.setKind(tok::annot_typename);
-    setTypeAnnotation(Tok, Classification.getType());
-    Tok.setAnnotationEndLoc(NameLoc);
+  case Sema::NC_Type: {
+    SourceLocation BeginLoc = NameLoc;
     if (SS.isNotEmpty())
-      Tok.setLocation(SS.getBeginLoc());
+      BeginLoc = SS.getBeginLoc();
+
+    /// An Objective-C object type followed by '<' is a specialization of
+    /// a parameterized class type or a protocol-qualified type.
+    ParsedType Ty = Classification.getType();
+    if (getLangOpts().ObjC1 && NextToken().is(tok::less) &&
+        (Ty.get()->isObjCObjectType() ||
+         Ty.get()->isObjCObjectPointerType())) {
+      // Consume the name.
+      SourceLocation IdentifierLoc = ConsumeToken();
+      SourceLocation NewEndLoc;
+      TypeResult NewType
+          = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty,
+                                                   /*consumeLastToken=*/false,
+                                                   NewEndLoc);
+      if (NewType.isUsable())
+        Ty = NewType.get();
+    }
+
+    Tok.setKind(tok::annot_typename);
+    setTypeAnnotation(Tok, Ty);
+    Tok.setAnnotationEndLoc(Tok.getLocation());
+    Tok.setLocation(BeginLoc);
     PP.AnnotateCachedTokens(Tok);
     return ANK_Success;
+  }
 
   case Sema::NC_Expression:
     Tok.setKind(tok::annot_primary_expr);
@@ -1627,13 +1648,33 @@ bool Parser::TryAnnotateTypeOrScopeToken
       // A FixIt was applied as a result of typo correction
       if (CorrectedII)
         Tok.setIdentifierInfo(CorrectedII);
+
+      SourceLocation BeginLoc = Tok.getLocation();
+      if (SS.isNotEmpty()) // it was a C++ qualified type name.
+        BeginLoc = SS.getBeginLoc();
+
+      /// An Objective-C object type followed by '<' is a specialization of
+      /// a parameterized class type or a protocol-qualified type.
+      if (getLangOpts().ObjC1 && NextToken().is(tok::less) &&
+          (Ty.get()->isObjCObjectType() ||
+           Ty.get()->isObjCObjectPointerType())) {
+        // Consume the name.
+        SourceLocation IdentifierLoc = ConsumeToken();
+        SourceLocation NewEndLoc;
+        TypeResult NewType
+          = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty,
+                                                   /*consumeLastToken=*/false,
+                                                   NewEndLoc);
+        if (NewType.isUsable())
+          Ty = NewType.get();
+      }
+
       // This is a typename. Replace the current token in-place with an
       // annotation type token.
       Tok.setKind(tok::annot_typename);
       setTypeAnnotation(Tok, Ty);
       Tok.setAnnotationEndLoc(Tok.getLocation());
-      if (SS.isNotEmpty()) // it was a C++ qualified type name.
-        Tok.setLocation(SS.getBeginLoc());
+      Tok.setLocation(BeginLoc);
 
       // In case the tokens were cached, have Preprocessor replace
       // them with the annotation token.

Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Sema/DeclSpec.cpp Mon Jul  6 22:58:14 2015
@@ -893,7 +893,6 @@ bool DeclSpec::SetConstexprSpec(SourceLo
   return false;
 }
 
-
 bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec,
                               unsigned &DiagID) {
   if (Concept_specified) {
@@ -906,30 +905,6 @@ bool DeclSpec::SetConceptSpec(SourceLoca
   return false;
 }
 
-void DeclSpec::setObjCTypeArgs(SourceLocation lAngleLoc,
-                               ArrayRef<ParsedType> args,
-                               SourceLocation rAngleLoc) {
-  ParsedType *argsCopy = new ParsedType[args.size()];
-  memcpy(argsCopy, args.data(), args.size() * sizeof(ParsedType));
-  ObjCTypeArgs = llvm::makeArrayRef(argsCopy, args.size());
-  ObjCTypeArgsLAngleLoc = lAngleLoc;
-  ObjCTypeArgsRAngleLoc = rAngleLoc;
-}
-
-void DeclSpec::setProtocolQualifiers(Decl * const *Protos,
-                                     unsigned NP,
-                                     SourceLocation *ProtoLocs,
-                                     SourceLocation LAngleLoc) {
-  if (NP == 0) return;
-  Decl **ProtoQuals = new Decl*[NP];
-  memcpy(ProtoQuals, Protos, sizeof(Decl*)*NP);
-  ProtocolQualifiers = ProtoQuals;
-  ProtocolLocs = new SourceLocation[NP];
-  memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP);
-  NumProtocolQualifiers = NP;
-  ProtocolLAngleLoc = LAngleLoc;
-}
-
 void DeclSpec::SaveWrittenBuiltinSpecs() {
   writtenBS.Sign = getTypeSpecSign();
   writtenBS.Width = getTypeSpecWidth();

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Jul  6 22:58:14 2015
@@ -560,29 +560,19 @@ ActOnSuperClassOfClassInterface(Scope *S
 
     // Handle type arguments on the superclass.
     TypeSourceInfo *SuperClassTInfo = nullptr;
-    if (!SuperTypeArgs.empty()) {
-      // Form declaration specifiers naming this superclass type with
-      // type arguments.
-      AttributeFactory attrFactory;
-      DeclSpec DS(attrFactory);
-      const char* prevSpec; // unused
-      unsigned diagID; // unused
-      TypeSourceInfo *parsedTSInfo
-        = Context.getTrivialTypeSourceInfo(SuperClassType, SuperLoc);
-      ParsedType parsedType = CreateParsedType(SuperClassType, parsedTSInfo);
-
-      DS.SetTypeSpecType(DeclSpec::TST_typename, SuperLoc, prevSpec, diagID,
-                         parsedType, Context.getPrintingPolicy());
-      DS.SetRangeStart(SuperLoc);
-      DS.SetRangeEnd(SuperLoc);
-      DS.setObjCTypeArgs(SuperTypeArgsRange.getBegin(),
-                         SuperTypeArgs,
-                         SuperTypeArgsRange.getEnd());
-
-      // Form the declarator.
-      Declarator D(DS, Declarator::TypeNameContext);
-     
-      TypeResult fullSuperClassType = ActOnTypeName(S, D);
+    if (!SuperTypeArgs.empty()) {     
+      TypeResult fullSuperClassType = actOnObjCTypeArgsAndProtocolQualifiers(
+                                        S,
+                                        SuperLoc,
+                                        CreateParsedType(SuperClassType, 
+                                                         nullptr),
+                                        SuperTypeArgsRange.getBegin(),
+                                        SuperTypeArgs,
+                                        SuperTypeArgsRange.getEnd(),
+                                        SourceLocation(),
+                                        { },
+                                        { },
+                                        SourceLocation());
       if (!fullSuperClassType.isUsable())
         return;
 
@@ -1230,21 +1220,26 @@ class ObjCTypeArgOrProtocolValidatorCCC
 
 void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
        Scope *S,
-       DeclSpec &DS,
        SourceLocation lAngleLoc,
        ArrayRef<IdentifierInfo *> identifiers,
        ArrayRef<SourceLocation> identifierLocs,
        SourceLocation rAngleLoc,
+       SourceLocation &typeArgsLAngleLoc,
+       SmallVectorImpl<ParsedType> &typeArgs,
+       SourceLocation &typeArgsRAngleLoc,
+       SourceLocation &protocolLAngleLoc,
+       SmallVectorImpl<Decl *> &protocols,
+       SourceLocation &protocolRAngleLoc,
        bool warnOnIncompleteProtocols) {
   // Local function that updates the declaration specifiers with
   // protocol information.
-  SmallVector<ObjCProtocolDecl *, 4> protocols;
   unsigned numProtocolsResolved = 0;
   auto resolvedAsProtocols = [&] {
     assert(numProtocolsResolved == identifiers.size() && "Unresolved protocols");
     
     for (unsigned i = 0, n = protocols.size(); i != n; ++i) {
-      ObjCProtocolDecl *&proto = protocols[i];
+      ObjCProtocolDecl *&proto 
+        = reinterpret_cast<ObjCProtocolDecl *&>(protocols[i]);
       // For an objc container, delay protocol reference checking until after we
       // can set the objc decl as the availability context, otherwise check now.
       if (!warnOnIncompleteProtocols) {
@@ -1268,12 +1263,9 @@ void Sema::actOnObjCTypeArgsOrProtocolQu
       }
     }
 
-    DS.setProtocolQualifiers((Decl * const *)(protocols.data()),
-                             protocols.size(),
-                             const_cast<SourceLocation *>(identifierLocs.data()),
-                             lAngleLoc);
-    if (rAngleLoc.isValid())
-      DS.SetRangeEnd(rAngleLoc);
+    protocolLAngleLoc = lAngleLoc;
+    protocolRAngleLoc = rAngleLoc;
+    assert(protocols.size() == identifierLocs.size());
   };
 
   // Attempt to resolve all of the identifiers as protocols.
@@ -1370,20 +1362,24 @@ void Sema::actOnObjCTypeArgsOrProtocolQu
   // Local function that updates the declaration specifiers with
   // type argument information.
   auto resolvedAsTypeDecls = [&] {
+    // We did not resolve these as protocols.
+    protocols.clear();
+
     assert(numTypeDeclsResolved == identifiers.size() && "Unresolved type decl");
     // Map type declarations to type arguments.
-    SmallVector<ParsedType, 4> typeArgs;
     for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
       // Map type reference to a type.
       TypeResult type = resolveTypeReference(typeDecls[i], identifierLocs[i]);
-      if (!type.isUsable())
+      if (!type.isUsable()) {
+        typeArgs.clear();
         return;
+      }
 
       typeArgs.push_back(type.get());
     }
 
-    // Record the Objective-C type arguments.
-    DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+    typeArgsLAngleLoc = lAngleLoc;
+    typeArgsRAngleLoc = rAngleLoc;
   };
 
   // If all of the identifiers can be resolved as type names or
@@ -1432,6 +1428,8 @@ void Sema::actOnObjCTypeArgsOrProtocolQu
         << identifiers[0]
         << SourceRange(identifierLocs[0]);
 
+      protocols.clear();
+      typeArgs.clear();
       return;
     }
 
@@ -1483,6 +1481,8 @@ void Sema::actOnObjCTypeArgsOrProtocolQu
           : lookupKind == LookupObjCProtocolName ? diag::err_undeclared_protocol
           : diag::err_unknown_typename))
       << identifiers[i];
+    protocols.clear();
+    typeArgs.clear();
     return;
   }
 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jul  6 22:58:14 2015
@@ -740,14 +740,18 @@ static void diagnoseAndRemoveTypeQualifi
 
 /// Apply Objective-C type arguments to the given type.
 static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
-                                  ArrayRef<ParsedType> typeArgs,
-                                  SourceRange typeArgsRange) {
+                                  ArrayRef<TypeSourceInfo *> typeArgs,
+                                  SourceRange typeArgsRange,
+                                  bool failOnError = false) {
   // We can only apply type arguments to an Objective-C class type.
   const auto *objcObjectType = type->getAs<ObjCObjectType>();
   if (!objcObjectType || !objcObjectType->getInterface()) {
     S.Diag(loc, diag::err_objc_type_args_non_class)
       << type
       << typeArgsRange;
+
+    if (failOnError)
+      return QualType();
     return type;
   }
 
@@ -758,6 +762,10 @@ static QualType applyObjCTypeArgs(Sema &
     S.Diag(loc, diag::err_objc_type_args_non_parameterized_class)
       << objcClass->getDeclName()
       << FixItHint::CreateRemoval(typeArgsRange);
+
+    if (failOnError)
+      return QualType();
+
     return type;
   }
 
@@ -766,26 +774,20 @@ static QualType applyObjCTypeArgs(Sema &
     S.Diag(loc, diag::err_objc_type_args_specialized_class)
       << type
       << FixItHint::CreateRemoval(typeArgsRange);
-    return type;
-  }
 
-  // Make sure that we have the right number of type arguments.
-  if (typeArgs.size() != typeParams->size()) {
-    S.Diag(loc, diag::err_objc_type_args_wrong_arity)
-      << (typeArgs.size() < typeParams->size())
-      << objcClass->getDeclName()
-      << (unsigned)typeArgs.size()
-      << (unsigned)typeParams->size();
-    S.Diag(objcClass->getLocation(), diag::note_previous_decl)
-      << objcClass;
+    if (failOnError)
+      return QualType();
+
     return type;
   }
 
   // Check the type arguments.
   SmallVector<QualType, 4> finalTypeArgs;
+  unsigned numTypeParams = typeParams->size();
+  bool anyPackExpansions = false;
   for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) {
-    TypeSourceInfo *typeArgInfo = nullptr;
-    QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo);
+    TypeSourceInfo *typeArgInfo = typeArgs[i];
+    QualType typeArg = typeArgInfo->getType();
 
     // Type arguments cannot explicitly specify nullability.
     if (auto nullability = AttributedType::stripOuterNullability(typeArg)) {
@@ -801,10 +803,42 @@ static QualType applyObjCTypeArgs(Sema &
 
     finalTypeArgs.push_back(typeArg);
 
+    if (typeArg->getAs<PackExpansionType>())
+      anyPackExpansions = true;
+
+    // Find the corresponding type parameter, if there is one.
+    ObjCTypeParamDecl *typeParam = nullptr;
+    if (!anyPackExpansions) {
+      if (i < numTypeParams) {
+        typeParam = typeParams->begin()[i];
+      } else {
+        // Too many arguments.
+        S.Diag(loc, diag::err_objc_type_args_wrong_arity)
+          << false
+          << objcClass->getDeclName()
+          << (unsigned)typeArgs.size()
+          << numTypeParams;
+        S.Diag(objcClass->getLocation(), diag::note_previous_decl)
+          << objcClass;
+
+        if (failOnError)
+          return QualType();
+
+        return type;
+      }
+    }
+
     // Objective-C object pointer types must be substitutable for the bounds.
     if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) {
+      // If we don't have a type parameter to match against, assume
+      // everything is fine. There was a prior pack expansion that
+      // means we won't be able to match anything.
+      if (!typeParam) {
+        assert(anyPackExpansions && "Too many arguments?");
+        continue;
+      }
+
       // Retrieve the bound.
-      ObjCTypeParamDecl *typeParam = typeParams->begin()[i];
       QualType bound = typeParam->getUnderlyingType();
       const auto *boundObjC = bound->getAs<ObjCObjectPointerType>();
 
@@ -826,13 +860,23 @@ static QualType applyObjCTypeArgs(Sema &
       S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here)
         << typeParam->getDeclName();
 
+      if (failOnError)
+        return QualType();
+
       return type;
     }
 
     // Block pointer types are permitted for unqualified 'id' bounds.
     if (typeArg->isBlockPointerType()) {
+      // If we don't have a type parameter to match against, assume
+      // everything is fine. There was a prior pack expansion that
+      // means we won't be able to match anything.
+      if (!typeParam) {
+        assert(anyPackExpansions && "Too many arguments?");
+        continue;
+      }
+
       // Retrieve the bound.
-      ObjCTypeParamDecl *typeParam = typeParams->begin()[i];
       QualType bound = typeParam->getUnderlyingType();
       if (bound->isBlockCompatibleObjCPointerType(S.Context))
         continue;
@@ -844,6 +888,9 @@ static QualType applyObjCTypeArgs(Sema &
       S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here)
         << typeParam->getDeclName();
 
+      if (failOnError)
+        return QualType();
+
       return type;
     }
 
@@ -857,6 +904,26 @@ static QualType applyObjCTypeArgs(Sema &
            diag::err_objc_type_arg_not_id_compatible)
       << typeArg
       << typeArgInfo->getTypeLoc().getSourceRange();
+
+    if (failOnError)
+      return QualType();
+
+    return type;
+  }
+
+  // Make sure we didn't have the wrong number of arguments.
+  if (!anyPackExpansions && finalTypeArgs.size() != numTypeParams) {
+    S.Diag(loc, diag::err_objc_type_args_wrong_arity)
+      << (typeArgs.size() < typeParams->size())
+      << objcClass->getDeclName()
+      << (unsigned)finalTypeArgs.size()
+      << (unsigned)numTypeParams;
+    S.Diag(objcClass->getLocation(), diag::note_previous_decl)
+      << objcClass;
+
+    if (failOnError)
+      return QualType();
+
     return type;
   }
 
@@ -868,7 +935,8 @@ static QualType applyObjCTypeArgs(Sema &
 static QualType applyObjCProtocolQualifiers(
                   Sema &S, SourceLocation loc, SourceRange range, QualType type,
                   ArrayRef<ObjCProtocolDecl *> protocols,
-                  const SourceLocation *protocolLocs) {
+                  const SourceLocation *protocolLocs,
+                  bool failOnError = false) {
   ASTContext &ctx = S.Context;
   if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){
     // FIXME: Check for protocols to which the class type is already
@@ -902,9 +970,185 @@ static QualType applyObjCProtocolQualifi
 
   S.Diag(loc, diag::err_invalid_protocol_qualifiers)
     << range;
+
+  if (failOnError)
+    return QualType();
+
   return type;
 }
 
+QualType Sema::BuildObjCObjectType(QualType BaseType,
+                                   SourceLocation Loc,
+                                   SourceLocation TypeArgsLAngleLoc,
+                                   ArrayRef<TypeSourceInfo *> TypeArgs,
+                                   SourceLocation TypeArgsRAngleLoc,
+                                   SourceLocation ProtocolLAngleLoc,
+                                   ArrayRef<ObjCProtocolDecl *> Protocols,
+                                   ArrayRef<SourceLocation> ProtocolLocs,
+                                   SourceLocation ProtocolRAngleLoc,
+                                   bool FailOnError) {
+  QualType Result = BaseType;
+  if (!TypeArgs.empty()) {
+    Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs,
+                               SourceRange(TypeArgsLAngleLoc,
+                                           TypeArgsRAngleLoc),
+                               FailOnError);
+    if (FailOnError && Result.isNull())
+      return QualType();
+  }
+
+  if (!Protocols.empty()) {
+    Result = applyObjCProtocolQualifiers(*this, Loc,
+                                         SourceRange(ProtocolLAngleLoc,
+                                                     ProtocolRAngleLoc),
+                                         Result, Protocols,
+                                         ProtocolLocs.data(),
+                                         FailOnError);
+    if (FailOnError && Result.isNull())
+      return QualType();
+  }
+
+  return Result;
+}
+
+TypeResult Sema::actOnObjCProtocolQualifierType(
+             SourceLocation lAngleLoc,
+             ArrayRef<Decl *> protocols,
+             ArrayRef<SourceLocation> protocolLocs,
+             SourceLocation rAngleLoc) {
+  // Form id<protocol-list>.
+  QualType Result = Context.getObjCObjectType(
+                      Context.ObjCBuiltinIdTy, { },
+                      llvm::makeArrayRef(
+                        (ObjCProtocolDecl * const *)protocols.data(),
+                        protocols.size()));
+  Result = Context.getObjCObjectPointerType(Result);
+
+  TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
+  TypeLoc ResultTL = ResultTInfo->getTypeLoc();
+
+  auto ObjCObjectPointerTL = ResultTL.castAs<ObjCObjectPointerTypeLoc>();
+  ObjCObjectPointerTL.setStarLoc(SourceLocation()); // implicit
+
+  auto ObjCObjectTL = ObjCObjectPointerTL.getPointeeLoc()
+                        .castAs<ObjCObjectTypeLoc>();
+  ObjCObjectTL.setHasBaseTypeAsWritten(false);
+  ObjCObjectTL.getBaseLoc().initialize(Context, SourceLocation());
+
+  // No type arguments.
+  ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation());
+  ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation());
+
+  // Fill in protocol qualifiers.
+  ObjCObjectTL.setProtocolLAngleLoc(lAngleLoc);
+  ObjCObjectTL.setProtocolRAngleLoc(rAngleLoc);
+  for (unsigned i = 0, n = protocols.size(); i != n; ++i)
+    ObjCObjectTL.setProtocolLoc(i, protocolLocs[i]);
+
+  // We're done. Return the completed type to the parser.
+  return CreateParsedType(Result, ResultTInfo);
+}
+
+TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
+             Scope *S,
+             SourceLocation Loc,
+             ParsedType BaseType,
+             SourceLocation TypeArgsLAngleLoc,
+             ArrayRef<ParsedType> TypeArgs,
+             SourceLocation TypeArgsRAngleLoc,
+             SourceLocation ProtocolLAngleLoc,
+             ArrayRef<Decl *> Protocols,
+             ArrayRef<SourceLocation> ProtocolLocs,
+             SourceLocation ProtocolRAngleLoc) {
+  TypeSourceInfo *BaseTypeInfo = nullptr;
+  QualType T = GetTypeFromParser(BaseType, &BaseTypeInfo);
+  if (T.isNull())
+    return true;
+
+  // Handle missing type-source info.
+  if (!BaseTypeInfo)
+    BaseTypeInfo = Context.getTrivialTypeSourceInfo(T, Loc);
+
+  // Extract type arguments.
+  SmallVector<TypeSourceInfo *, 4> ActualTypeArgInfos;
+  for (unsigned i = 0, n = TypeArgs.size(); i != n; ++i) {
+    TypeSourceInfo *TypeArgInfo = nullptr;
+    QualType TypeArg = GetTypeFromParser(TypeArgs[i], &TypeArgInfo);
+    if (TypeArg.isNull()) {
+      ActualTypeArgInfos.clear();
+      break;
+    }
+    
+    assert(TypeArgInfo && "No type source info?");
+    ActualTypeArgInfos.push_back(TypeArgInfo);
+  }
+
+  // Build the object type.
+  QualType Result = BuildObjCObjectType(
+                      T, 
+                      BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(),
+                      TypeArgsLAngleLoc, 
+                      ActualTypeArgInfos, 
+                      TypeArgsRAngleLoc,
+                      ProtocolLAngleLoc,
+                      llvm::makeArrayRef((ObjCProtocolDecl **)Protocols.data(),
+                                         Protocols.size()),
+                      ProtocolLocs,
+                      ProtocolRAngleLoc,
+                      /*FailOnError=*/false);
+
+  if (Result == T)
+    return BaseType;
+    
+  // Create source information for this type.
+  TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
+  TypeLoc ResultTL = ResultTInfo->getTypeLoc();
+
+  // For id<Proto1, Proto2> or Class<Proto1, Proto2>, we'll have an
+  // object pointer type. Fill in source information for it.
+  if (auto ObjCObjectPointerTL = ResultTL.getAs<ObjCObjectPointerTypeLoc>()) {
+    // The '*' is implicit.
+    ObjCObjectPointerTL.setStarLoc(SourceLocation());
+    ResultTL = ObjCObjectPointerTL.getPointeeLoc();
+  }
+
+  auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>();
+
+  // Type argument information.
+  if (ObjCObjectTL.getNumTypeArgs() > 0) {
+    assert(ObjCObjectTL.getNumTypeArgs() == ActualTypeArgInfos.size());
+    ObjCObjectTL.setTypeArgsLAngleLoc(TypeArgsLAngleLoc);
+    ObjCObjectTL.setTypeArgsRAngleLoc(TypeArgsRAngleLoc);
+    for (unsigned i = 0, n = ActualTypeArgInfos.size(); i != n; ++i)
+      ObjCObjectTL.setTypeArgTInfo(i, ActualTypeArgInfos[i]);
+  } else {
+    ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation());
+    ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation());
+  }
+
+  // Protocol qualifier information.
+  if (ObjCObjectTL.getNumProtocols() > 0) {
+    assert(ObjCObjectTL.getNumProtocols() == Protocols.size());
+    ObjCObjectTL.setProtocolLAngleLoc(ProtocolLAngleLoc);
+    ObjCObjectTL.setProtocolRAngleLoc(ProtocolRAngleLoc);
+    for (unsigned i = 0, n = Protocols.size(); i != n; ++i)
+      ObjCObjectTL.setProtocolLoc(i, ProtocolLocs[i]);
+  } else {
+    ObjCObjectTL.setProtocolLAngleLoc(SourceLocation());
+    ObjCObjectTL.setProtocolRAngleLoc(SourceLocation());
+  }
+
+  // Base type.
+  ObjCObjectTL.setHasBaseTypeAsWritten(true);
+  if (ObjCObjectTL.getType() == T)
+    ObjCObjectTL.getBaseLoc().initializeFullCopy(BaseTypeInfo->getTypeLoc());
+  else
+    ObjCObjectTL.getBaseLoc().initialize(Context, Loc);
+
+  // We're done. Return the completed type to the parser.
+  return CreateParsedType(Result, ResultTInfo);
+}
+
 /// \brief Convert the specified declspec to the appropriate type
 /// object.
 /// \param state Specifies the declarator containing the declaration specifier
@@ -968,16 +1212,6 @@ static QualType ConvertDeclSpecToType(Ty
       Result = Context.Char32Ty;
     break;
   case DeclSpec::TST_unspecified:
-    // "<proto1,proto2>" is an objc qualified ID with a missing id.
-    if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
-      Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { },
-                                         llvm::makeArrayRef(
-                                           (ObjCProtocolDecl*const*)PQ,
-                                           DS.getNumProtocolQualifiers()));
-      Result = Context.getObjCObjectPointerType(Result);
-      break;
-    }
-
     // If this is a missing declspec in a block literal return context, then it
     // is inferred from the return statements inside the block.
     // The declspec is always missing in a lambda expr context; it is either
@@ -1161,21 +1395,6 @@ static QualType ConvertDeclSpecToType(Ty
           declarator.setInvalidType(true);
         }
       }
-    } else {
-      // Apply Objective-C type arguments.
-      if (DS.hasObjCTypeArgs()) {
-        Result = applyObjCTypeArgs(S, DeclLoc, Result, DS.getObjCTypeArgs(),
-                                   DS.getObjCTypeArgsRange());
-      }
-
-      // Apply Objective-C protocol qualifiers.
-      if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
-        Result = applyObjCProtocolQualifiers(
-                   S, DeclLoc, DS.getSourceRange(), Result,
-                   llvm::makeArrayRef((ObjCProtocolDecl * const *)PQ,
-                                      DS.getNumProtocolQualifiers()),
-                   DS.getProtocolLocs());
-      }
     }
 
     // TypeQuals handled by caller.
@@ -4282,47 +4501,14 @@ namespace {
       TL.setNameEndLoc(DS.getLocEnd());
     }
     void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
-      // Handle the base type, which might not have been written explicitly.
-      if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
-        TL.setHasBaseTypeAsWritten(false);
-        TL.getBaseLoc().initialize(Context, SourceLocation());
-      } else {
-        TL.setHasBaseTypeAsWritten(true);
-        Visit(TL.getBaseLoc());
-      }
-
-      // Type arguments.
-      if (TL.getNumTypeArgs() > 0) {
-        assert(TL.getNumTypeArgs() == DS.getObjCTypeArgs().size());
-        TL.setTypeArgsLAngleLoc(DS.getObjCTypeArgsLAngleLoc());
-        TL.setTypeArgsRAngleLoc(DS.getObjCTypeArgsRAngleLoc());
-        for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) {
-          TypeSourceInfo *typeArgInfo = nullptr;
-          (void)Sema::GetTypeFromParser(DS.getObjCTypeArgs()[i], &typeArgInfo);
-          TL.setTypeArgTInfo(i, typeArgInfo);
-        }
-      } else {
-        TL.setTypeArgsLAngleLoc(SourceLocation());
-        TL.setTypeArgsRAngleLoc(SourceLocation());
-      }
-
-      // Protocol qualifiers.
-      if (DS.getProtocolQualifiers()) {
-        assert(TL.getNumProtocols() > 0);
-        assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
-        TL.setProtocolLAngleLoc(DS.getProtocolLAngleLoc());
-        TL.setProtocolRAngleLoc(DS.getSourceRange().getEnd());
-        for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i)
-          TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
-      } else {
-        assert(TL.getNumProtocols() == 0);
-        TL.setProtocolLAngleLoc(SourceLocation());
-        TL.setProtocolRAngleLoc(SourceLocation());
-      }
+      TypeSourceInfo *RepTInfo = nullptr;
+      Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo);
+      TL.copy(RepTInfo->getTypeLoc());
     }
     void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
-      TL.setStarLoc(SourceLocation());
-      Visit(TL.getPointeeLoc());
+      TypeSourceInfo *RepTInfo = nullptr;
+      Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo);
+      TL.copy(RepTInfo->getTypeLoc());
     }
     void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
       TypeSourceInfo *TInfo = nullptr;

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Jul  6 22:58:14 2015
@@ -685,6 +685,27 @@ public:
   QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType,
                                     SourceLocation Sigil);
 
+  /// \brief Build an Objective-C object type.
+  ///
+  /// By default, performs semantic analysis when building the object type.
+  /// Subclasses may override this routine to provide different behavior.
+  QualType RebuildObjCObjectType(QualType BaseType,
+                                 SourceLocation Loc,
+                                 SourceLocation TypeArgsLAngleLoc,
+                                 ArrayRef<TypeSourceInfo *> TypeArgs,
+                                 SourceLocation TypeArgsRAngleLoc,
+                                 SourceLocation ProtocolLAngleLoc,
+                                 ArrayRef<ObjCProtocolDecl *> Protocols,
+                                 ArrayRef<SourceLocation> ProtocolLocs,
+                                 SourceLocation ProtocolRAngleLoc);
+
+  /// \brief Build a new Objective-C object pointer type given the pointee type.
+  ///
+  /// By default, directly builds the pointer type, with no additional semantic
+  /// analysis.
+  QualType RebuildObjCObjectPointerType(QualType PointeeType,
+                                        SourceLocation Star);
+
   /// \brief Build a new array type given the element type, size
   /// modifier, size of the array (if known), size expression, and index type
   /// qualifiers.
@@ -5606,18 +5627,153 @@ template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
                                                 ObjCObjectTypeLoc TL) {
-  // ObjCObjectType is never dependent.
-  TLB.pushFullCopy(TL);
-  return TL.getType();
+  // Transform base type.
+  QualType BaseType = getDerived().TransformType(TLB, TL.getBaseLoc());
+  if (BaseType.isNull())
+    return QualType();
+
+  bool AnyChanged = BaseType != TL.getBaseLoc().getType();
+
+  // Transform type arguments.
+  SmallVector<TypeSourceInfo *, 4> NewTypeArgInfos;
+  for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) {
+    TypeSourceInfo *TypeArgInfo = TL.getTypeArgTInfo(i);
+    TypeLoc TypeArgLoc = TypeArgInfo->getTypeLoc();
+    QualType TypeArg = TypeArgInfo->getType();
+    if (auto PackExpansionLoc = TypeArgLoc.getAs<PackExpansionTypeLoc>()) {
+      AnyChanged = true;
+
+      // We have a pack expansion. Instantiate it.
+      const auto *PackExpansion = PackExpansionLoc.getType()
+                                    ->castAs<PackExpansionType>();
+      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+      SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
+                                              Unexpanded);
+      assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+      // Determine whether the set of unexpanded parameter packs can
+      // and should be expanded.
+      TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc();
+      bool Expand = false;
+      bool RetainExpansion = false;
+      Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
+      if (getDerived().TryExpandParameterPacks(
+            PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
+            Unexpanded, Expand, RetainExpansion, NumExpansions))
+        return QualType();
+
+      if (!Expand) {
+        // We can't expand this pack expansion into separate arguments yet;
+        // just substitute into the pattern and create a new pack expansion
+        // type.
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+
+        TypeLocBuilder TypeArgBuilder;
+        TypeArgBuilder.reserve(PatternLoc.getFullDataSize());
+        QualType NewPatternType = getDerived().TransformType(TypeArgBuilder, 
+                                                             PatternLoc);
+        if (NewPatternType.isNull())
+          return QualType();
+
+        QualType NewExpansionType = SemaRef.Context.getPackExpansionType(
+                                      NewPatternType, NumExpansions);
+        auto NewExpansionLoc = TLB.push<PackExpansionTypeLoc>(NewExpansionType);
+        NewExpansionLoc.setEllipsisLoc(PackExpansionLoc.getEllipsisLoc());
+        NewTypeArgInfos.push_back(
+          TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewExpansionType));
+        continue;
+      }
+
+      // Substitute into the pack expansion pattern for each slice of the
+      // pack.
+      for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx);
+
+        TypeLocBuilder TypeArgBuilder;
+        TypeArgBuilder.reserve(PatternLoc.getFullDataSize());
+
+        QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder,
+                                                         PatternLoc);
+        if (NewTypeArg.isNull())
+          return QualType();
+
+        NewTypeArgInfos.push_back(
+          TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg));
+      }
+
+      continue;
+    }
+
+    TypeLocBuilder TypeArgBuilder;
+    TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize());
+    QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc);
+    if (NewTypeArg.isNull())
+      return QualType();
+
+    // If nothing changed, just keep the old TypeSourceInfo.
+    if (NewTypeArg == TypeArg) {
+      NewTypeArgInfos.push_back(TypeArgInfo);
+      continue;
+    }
+
+    NewTypeArgInfos.push_back(
+      TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg));
+    AnyChanged = true;
+  }
+
+  QualType Result = TL.getType();
+  if (getDerived().AlwaysRebuild() || AnyChanged) {
+    // Rebuild the type.
+    Result = getDerived().RebuildObjCObjectType(
+               BaseType,
+               TL.getLocStart(),
+               TL.getTypeArgsLAngleLoc(),
+               NewTypeArgInfos,
+               TL.getTypeArgsRAngleLoc(),
+               TL.getProtocolLAngleLoc(),
+               llvm::makeArrayRef(TL.getTypePtr()->qual_begin(),
+                                  TL.getNumProtocols()),
+               TL.getProtocolLocs(),
+               TL.getProtocolRAngleLoc());
+
+    if (Result.isNull())
+      return QualType();
+  }
+
+  ObjCObjectTypeLoc NewT = TLB.push<ObjCObjectTypeLoc>(Result);
+  assert(TL.hasBaseTypeAsWritten() && "Can't be dependent");
+  NewT.setHasBaseTypeAsWritten(true);
+  NewT.setTypeArgsLAngleLoc(TL.getTypeArgsLAngleLoc());
+  for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
+    NewT.setTypeArgTInfo(i, NewTypeArgInfos[i]);
+  NewT.setTypeArgsRAngleLoc(TL.getTypeArgsRAngleLoc());
+  NewT.setProtocolLAngleLoc(TL.getProtocolLAngleLoc());
+  for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i)
+    NewT.setProtocolLoc(i, TL.getProtocolLoc(i));
+  NewT.setProtocolRAngleLoc(TL.getProtocolRAngleLoc());
+  return Result;
 }
 
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
                                                ObjCObjectPointerTypeLoc TL) {
-  // ObjCObjectPointerType is never dependent.
-  TLB.pushFullCopy(TL);
-  return TL.getType();
+  QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc());
+  if (PointeeType.isNull())
+    return QualType();
+
+  QualType Result = TL.getType();
+  if (getDerived().AlwaysRebuild() ||
+      PointeeType != TL.getPointeeLoc().getType()) {
+    Result = getDerived().RebuildObjCObjectPointerType(PointeeType,
+                                                       TL.getStarLoc());
+    if (Result.isNull())
+      return QualType();
+  }
+
+  ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
+  NewT.setStarLoc(TL.getStarLoc());
+  return Result;
 }
 
 //===----------------------------------------------------------------------===//
@@ -10494,6 +10650,31 @@ TreeTransform<Derived>::RebuildMemberPoi
 }
 
 template<typename Derived>
+QualType TreeTransform<Derived>::RebuildObjCObjectType(
+           QualType BaseType,
+           SourceLocation Loc,
+           SourceLocation TypeArgsLAngleLoc,
+           ArrayRef<TypeSourceInfo *> TypeArgs,
+           SourceLocation TypeArgsRAngleLoc,
+           SourceLocation ProtocolLAngleLoc,
+           ArrayRef<ObjCProtocolDecl *> Protocols,
+           ArrayRef<SourceLocation> ProtocolLocs,
+           SourceLocation ProtocolRAngleLoc) {
+  return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc,
+                                     TypeArgs, TypeArgsRAngleLoc,
+                                     ProtocolLAngleLoc, Protocols, ProtocolLocs,
+                                     ProtocolRAngleLoc,
+                                     /*FailOnError=*/true);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildObjCObjectPointerType(
+           QualType PointeeType,
+           SourceLocation Star) {
+  return SemaRef.Context.getObjCObjectPointerType(PointeeType);
+}
+
+template<typename Derived>
 QualType
 TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
                                          ArrayType::ArraySizeModifier SizeMod,

Modified: cfe/trunk/test/Index/annotate-parameterized-classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-parameterized-classes.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/Index/annotate-parameterized-classes.m (original)
+++ cfe/trunk/test/Index/annotate-parameterized-classes.m Mon Jul  6 22:58:14 2015
@@ -17,19 +17,15 @@ typedef A<id<NSObject>, NSObject *> ASpe
 
 // RUN: c-index-test -test-annotate-tokens=%s:7:1:9:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-INTERFACE-DECL %s
 // CHECK-INTERFACE-DECL: Identifier: "T" [7:14 - 7:15] TemplateTypeParameter=T:7:14
-// FIXME: Should be a type reference
-// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TemplateTypeParameter=T:7:14
+// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TypeRef=id:0:0
 // CHECK-INTERFACE-DECL: Identifier: "U" [7:22 - 7:23] TemplateTypeParameter=U:7:22
-// FIXME: Should be a class reference
-// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] TemplateTypeParameter=U:7:22
+// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] ObjCClassRef=NSObject:4:12
 
 // RUN: c-index-test -test-annotate-tokens=%s:10:1:12:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-CATEGORY-DECL %s
 // CHECK-CATEGORY-DECL: Identifier: "T" [10:14 - 10:15] TemplateTypeParameter=T:10:14 
-// FIXME: Should be a type reference
-// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TemplateTypeParameter=T:10:14
+// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TypeRef=id:0:0
 // CHECK-CATEGORY-DECL: Identifier: "U" [10:22 - 10:23] TemplateTypeParameter=U:10:22
-// FIXME: Should be a class reference
-// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] TemplateTypeParameter=U:10:22
+// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] ObjCClassRef=NSObject:4:12
 
 // RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SPECIALIZATION %s
 // CHECK-SPECIALIZATION: Identifier: "id" [13:11 - 13:13] TypeRef=id:0:0

Modified: cfe/trunk/test/Index/annotate-tokens.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-tokens.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/Index/annotate-tokens.m (original)
+++ cfe/trunk/test/Index/annotate-tokens.m Mon Jul  6 22:58:14 2015
@@ -152,6 +152,7 @@ static Rdar8595462_A * Rdar8595462_stati
   @property int extensionProperty;
 @end
 
+typedef id<Proto> *proto_ptr;
 
 // RUN: c-index-test -test-annotate-tokens=%s:1:1:118:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
 // CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
@@ -596,3 +597,9 @@ static Rdar8595462_A * Rdar8595462_stati
 // CHECK-PROP: Keyword: "property" [152:4 - 152:12] ObjCPropertyDecl=extensionProperty:152:17
 // CHECK-PROP: Keyword: "int" [152:13 - 152:16] ObjCPropertyDecl=extensionProperty:152:17
 // CHECK-PROP: Identifier: "extensionProperty" [152:17 - 152:34] ObjCPropertyDecl=extensionProperty:152:17
+
+// RUN: c-index-test -test-annotate-tokens=%s:155:1:156:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-ID-PROTO %s
+// CHECK-ID-PROTO: Identifier: "id" [155:9 - 155:11] TypeRef=id:0:0
+// CHECK-ID-PROTO: Punctuation: "<" [155:11 - 155:12] TypedefDecl=proto_ptr:155:20 (Definition)
+// CHECK-ID-PROTO: Identifier: "Proto" [155:12 - 155:17] ObjCProtocolRef=Proto
+// CHECK-ID-PROTO: Punctuation: ">" [155:17 - 155:18] TypedefDecl=proto_ptr:155:20 (Definition)

Modified: cfe/trunk/test/Parser/placeholder-recovery.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/placeholder-recovery.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/Parser/placeholder-recovery.m (original)
+++ cfe/trunk/test/Parser/placeholder-recovery.m Mon Jul  6 22:58:14 2015
@@ -3,10 +3,9 @@
 // FIXME: We could do much better with this, if we recognized
 // placeholders somehow. However, we're content with not generating
 // bogus 'archaic' warnings with bad location info.
- at protocol <#protocol name#> <NSObject> // expected-error 2{{expected identifier}} \
-// expected-error{{cannot find protocol declaration for 'NSObject'}} \
+ at protocol <#protocol name#> <NSObject> // expected-error {{expected identifier or '('}} \
+// expected-error 2{{expected identifier}} \
 // expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
+<#methods#>
 
-<#methods#>  // expected-error{{expected identifier}}
-
- at end // expected-error{{prefix attribute}}
+ at end

Modified: cfe/trunk/test/SemaObjC/parameterized_classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/parameterized_classes.m (original)
+++ cfe/trunk/test/SemaObjC/parameterized_classes.m Mon Jul  6 22:58:14 2015
@@ -1,5 +1,9 @@
 // RUN: %clang_cc1 -fblocks %s -verify
 
+#if !__has_feature(objc_generics)
+#  error Compiler does not support Objective-C generics?
+#endif
+
 @protocol NSObject // expected-note{{'NSObject' declared here}}
 @end
 
@@ -255,14 +259,14 @@ typedef PC15<int (^)(int, int), // block
 typedef PC15<NSObject *, NSObject *, id<NSCopying>> typeArgs8;
 
 typedef PC15<NSObject *, NSObject *,
-             NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}}
+             NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}}
 
 typedef PC15<id,
-             id,  // expected-error{{type argument 'id' does not satisy the bound ('NSObject *') of type parameter 'U'}}
+             id,  // expected-error{{type argument 'id' does not satisfy the bound ('NSObject *') of type parameter 'U'}}
              id> typeArgs9;
 
 typedef PC15<id, NSObject *,
-             id> typeArgs10; // expected-error{{type argument 'id' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}}
+             id> typeArgs10; // expected-error{{type argument 'id' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}}
 
 typedef PC15<id,
              int (^)(int, int), // okay
@@ -306,7 +310,7 @@ void testSpecializedTypePrinting() {
 @interface PC23<T : NSObject *> : PC1<T, U> // expected-error{{unknown type name 'U'}}
 @end
 
- at interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisy the bound ('NSObject *') of type parameter 'U'}}
+ at interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisfy the bound ('NSObject *') of type parameter 'U'}}
 @end
 
 @interface NSFoo : PC1<NSObject *, NSObject *> // okay

Modified: cfe/trunk/test/SemaObjC/protocol-archane.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/protocol-archane.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/protocol-archane.m (original)
+++ cfe/trunk/test/SemaObjC/protocol-archane.m Mon Jul  6 22:58:14 2015
@@ -40,3 +40,7 @@ Class <SomeProtocol> UnfortunateGCCExten
 - (void)crashWith:(<Broken>)a { // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
 }
 @end
+
+typedef <SomeProtocol> id TwoTypeSpecs; // expected-warning{{no object type specified}}
+// expected-error at -1{{typedef redefinition with different types ('id<SomeProtocol>' vs 'id')}}
+// expected-error at -2{{expected ';' after top level declarator}}

Added: cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm?rev=241545&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm (added)
+++ cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm Mon Jul  6 22:58:14 2015
@@ -0,0 +1,407 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -std=c++11 %s -verify
+//
+// Test the substitution of type arguments for type parameters when
+// using parameterized classes in Objective-C.
+
+__attribute__((objc_root_class))
+ at interface NSObject
++ (instancetype)alloc;
+- (instancetype)init;
+ at end
+
+ at protocol NSCopying
+ at end
+
+ at interface NSString : NSObject <NSCopying>
+ at end
+
+ at interface NSNumber : NSObject <NSCopying>
+ at end
+
+ at interface NSArray<T> : NSObject <NSCopying> {
+ at public
+  T *data; // don't try this at home
+}
+- (T)objectAtIndexedSubscript:(int)index;
++ (NSArray<T> *)array;
+ at property (copy,nonatomic) T lastObject;
+ at end
+
+ at interface NSMutableArray<T> : NSArray<T>
+-(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}}
+- (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}}
+ at end
+
+ at interface NSStringArray : NSArray<NSString *>
+ at end
+
+ at interface NSSet<T> : NSObject <NSCopying>
+- (T)firstObject;
+ at property (nonatomic, copy) NSArray<T> *allObjects;
+ at end
+
+// Parameterized inheritance (simple case)
+ at interface NSMutableSet<U : id<NSCopying>> : NSSet<U>
+- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}}
+ at end
+
+ at interface Widget : NSObject <NSCopying>
+ at end
+
+// Non-parameterized class inheriting from a specialization of a
+// parameterized class.
+ at interface WidgetSet : NSMutableSet<Widget *>
+ at end
+
+// Parameterized inheritance with a more interesting transformation in
+// the specialization.
+ at interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*>
+ at end
+
+// Inheriting from an unspecialized form of a parameterized type.
+ at interface UntypedMutableSet : NSMutableSet
+ at end
+
+ at interface Window : NSObject
+ at end
+
+ at interface NSDictionary<K, V> : NSObject <NSCopying>
+- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}}
+ at end
+
+ at interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V> // expected-note 2{{type parameter 'K' declared here}} \
+// expected-note 2{{'NSMutableDictionary' declared here}}
+- (void)setObject:(V)object forKeyedSubscript:(K)key;
+// expected-note at -1 {{parameter 'object' here}}
+// expected-note at -2 {{parameter 'object' here}}
+// expected-note at -3 {{parameter 'key' here}}
+// expected-note at -4 {{parameter 'key' here}}
+
+ at property (strong) K someRandomKey;
+ at end
+
+ at interface WindowArray : NSArray<Window *>
+ at end
+
+ at interface NSSet<T> (Searching)
+- (T)findObject:(T)object;
+ at end
+
+
+// --------------------------------------------------------------------------
+// Message sends.
+// --------------------------------------------------------------------------
+void test_message_send_result(
+       NSSet<NSString *> *stringSet,
+       NSMutableSet<NSString *> *mutStringSet,
+       WidgetSet *widgetSet,
+       UntypedMutableSet *untypedMutSet,
+       MutableSetOfArrays<NSString *> *mutStringArraySet,
+       NSSet *set,
+       NSMutableSet *mutSet,
+       MutableSetOfArrays *mutArraySet,
+       NSArray<NSString *> *stringArray,
+       void (^block)(void)) {
+  int *ip;
+  ip = [stringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}}
+  ip = [mutStringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}}
+  ip = [widgetSet firstObject]; // expected-error{{from incompatible type 'Widget *'}}
+  ip = [untypedMutSet firstObject]; // expected-error{{from incompatible type 'id'}}
+  ip = [mutStringArraySet firstObject]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+  ip = [set firstObject]; // expected-error{{from incompatible type 'id'}}
+  ip = [mutSet firstObject]; // expected-error{{from incompatible type 'id'}}
+  ip = [mutArraySet firstObject]; // expected-error{{from incompatible type 'id'}}
+  ip = [block firstObject]; // expected-error{{from incompatible type 'id'}}
+
+  ip = [stringSet findObject:@"blah"]; // expected-error{{from incompatible type 'NSString *'}}
+
+  // Class messages.
+  ip = [NSSet<NSString *> alloc]; // expected-error{{from incompatible type 'NSSet<NSString *> *'}}
+  ip = [NSSet alloc]; // expected-error{{from incompatible type 'NSSet *'}}
+  ip = [MutableSetOfArrays<NSString *> alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays<NSString *> *'}}
+  ip = [MutableSetOfArrays alloc];  // expected-error{{from incompatible type 'MutableSetOfArrays *'}}
+  ip = [NSArray<NSString *> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+  ip = [NSArray<NSString *><NSCopying> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+
+  ip = [[NSMutableArray<NSString *> alloc] init];  // expected-error{{from incompatible type 'NSMutableArray<NSString *> *'}}
+
+  [[NSMutableArray alloc] initWithArray: stringArray]; // okay
+  [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay
+  [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-error{{parameter of type 'NSArray<NSNumber *> *' with an lvalue of type 'NSArray<NSString *> *'}}
+}
+
+void test_message_send_param(
+       NSMutableSet<NSString *> *mutStringSet,
+       WidgetSet *widgetSet,
+       UntypedMutableSet *untypedMutSet,
+       MutableSetOfArrays<NSString *> *mutStringArraySet,
+       NSMutableSet *mutSet,
+       MutableSetOfArrays *mutArraySet,
+       void (^block)(void)) {
+  Window *window;
+
+  [mutStringSet addObject: window]; // expected-error{{parameter of type 'NSString *'}}
+  [widgetSet addObject: window]; // expected-error{{parameter of type 'Widget *'}}
+  [untypedMutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
+  [mutStringArraySet addObject: window]; // expected-error{{parameter of type 'NSArray<NSString *> *'}}
+  [mutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
+  [mutArraySet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
+  [block addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Property accesses.
+// --------------------------------------------------------------------------
+void test_property_read(
+       NSSet<NSString *> *stringSet,
+       NSMutableSet<NSString *> *mutStringSet,
+       WidgetSet *widgetSet,
+       UntypedMutableSet *untypedMutSet,
+       MutableSetOfArrays<NSString *> *mutStringArraySet,
+       NSSet *set,
+       NSMutableSet *mutSet,
+       MutableSetOfArrays *mutArraySet,
+       NSMutableDictionary *mutDict) {
+  int *ip;
+  ip = stringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+  ip = mutStringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+  ip = widgetSet.allObjects; // expected-error{{from incompatible type 'NSArray<Widget *> *'}}
+  ip = untypedMutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
+  ip = mutStringArraySet.allObjects; // expected-error{{from incompatible type 'NSArray<NSArray<NSString *> *> *'}}
+  ip = set.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
+  ip = mutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
+  ip = mutArraySet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
+
+  ip = mutDict.someRandomKey; // expected-error{{from incompatible type 'id'}}
+}
+
+void test_property_write(
+       NSMutableSet<NSString *> *mutStringSet,
+       WidgetSet *widgetSet,
+       UntypedMutableSet *untypedMutSet,
+       MutableSetOfArrays<NSString *> *mutStringArraySet,
+       NSMutableSet *mutSet,
+       MutableSetOfArrays *mutArraySet,
+       NSMutableDictionary *mutDict) {
+  int *ip;
+
+  mutStringSet.allObjects = ip; // expected-error{{to 'NSArray<NSString *> *'}}
+  widgetSet.allObjects = ip; // expected-error{{to 'NSArray<Widget *> *'}}
+  untypedMutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}
+  mutStringArraySet.allObjects = ip; // expected-error{{to 'NSArray<NSArray<NSString *> *> *'}}
+  mutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}
+  mutArraySet.allObjects = ip; // expected-error{{to 'NSArray *'}}
+
+  mutDict.someRandomKey = ip; // expected-error{{to 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Subscripting
+// --------------------------------------------------------------------------
+void test_subscripting(
+       NSArray<NSString *> *stringArray,
+       NSMutableArray<NSString *> *mutStringArray,
+       NSArray *array,
+       NSMutableArray *mutArray,
+       NSDictionary<NSString *, Widget *> *stringWidgetDict,
+       NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict,
+       NSDictionary *dict,
+       NSMutableDictionary *mutDict) {
+  int *ip;
+  NSString *string;
+  Widget *widget;
+  Window *window;
+
+  ip = stringArray[0]; // expected-error{{from incompatible type 'NSString *'}}
+
+  ip = mutStringArray[0]; // expected-error{{from incompatible type 'NSString *'}}
+  mutStringArray[0] = ip; // expected-error{{parameter of type 'NSString *'}}
+
+  ip = array[0]; // expected-error{{from incompatible type 'id'}}
+
+  ip = mutArray[0]; // expected-error{{from incompatible type 'id'}}
+  mutArray[0] = ip; // expected-error{{parameter of type 'id'}}
+
+  ip = stringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}}
+  widget = stringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
+
+  ip = mutStringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}}
+  widget = mutStringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
+  mutStringWidgetDict[string] = ip; // expected-error{{parameter of type 'Widget *'}}
+  mutStringWidgetDict[widget] = widget; // expected-error{{parameter of type 'NSString *'}}
+
+  ip = dict[string]; // expected-error{{from incompatible type 'id'}}
+
+  ip = mutDict[string]; // expected-error{{incompatible type 'id'}}
+  mutDict[string] = ip; // expected-error{{parameter of type 'id'}}
+
+  widget = mutDict[window];
+  mutDict[window] = widget; // expected-error{{parameter of type 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Instance variable access.
+// --------------------------------------------------------------------------
+void test_instance_variable(NSArray<NSString *> *stringArray,
+                            NSArray *array) {
+  int *ip;
+
+  ip = stringArray->data; // expected-error{{from incompatible type 'NSString **'}}
+  ip = array->data; // expected-error{{from incompatible type 'id *'}}
+}
+
+ at implementation WindowArray
+- (void)testInstanceVariable {
+  int *ip;
+
+  ip = data; // expected-error{{from incompatible type 'Window **'}}
+}
+ at end
+
+// --------------------------------------------------------------------------
+// Implicit conversions.
+// --------------------------------------------------------------------------
+void test_implicit_conversions(NSArray<NSString *> *stringArray,
+                               NSArray<NSNumber *> *numberArray,
+                               NSMutableArray<NSString *> *mutStringArray,
+                               NSArray *array,
+                               NSMutableArray *mutArray) {
+  // Specialized -> unspecialized (same level)
+  array = stringArray;
+
+  // Unspecialized -> specialized (same level)
+  stringArray = array;
+
+  // Specialized -> specialized failure (same level).
+  stringArray = numberArray; // expected-error{{assigning to 'NSArray<NSString *> *' from incompatible type 'NSArray<NSNumber *> *'}}
+
+  // Specialized -> specialized (different levels).
+  stringArray = mutStringArray;
+
+  // Specialized -> specialized failure (different levels).
+  numberArray = mutStringArray; // expected-error{{assigning to 'NSArray<NSNumber *> *' from incompatible type 'NSMutableArray<NSString *> *'}}
+
+  // Unspecialized -> specialized (different levels).
+  stringArray = mutArray;
+
+  // Specialized -> unspecialized (different levels).
+  array = mutStringArray;
+}
+
+// --------------------------------------------------------------------------
+// Ternary operator
+// --------------------------------------------------------------------------
+void test_ternary_operator(NSArray<NSString *> *stringArray,
+                           NSArray<NSNumber *> *numberArray,
+                           NSMutableArray<NSString *> *mutStringArray,
+                           NSStringArray *stringArray2,
+                           NSArray *array,
+                           NSMutableArray *mutArray,
+                           int cond) {
+  int *ip;
+  id object;
+
+  ip = cond ? stringArray : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+  ip = cond ? mutStringArray : stringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+
+  ip = cond ? stringArray2 : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+  ip = cond ? mutStringArray : stringArray2; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+
+  ip = cond ? stringArray : mutArray; // expected-error{{from incompatible type 'NSArray *'}}
+
+  ip = cond ? stringArray2 : mutArray; // expected-error{{from incompatible type 'NSArray *'}}
+
+  ip = cond ? mutArray : stringArray; // expected-error{{from incompatible type 'NSArray *'}}
+
+  ip = cond ? mutArray : stringArray2; // expected-error{{from incompatible type 'NSArray *'}}
+
+  object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}}
+}
+
+// --------------------------------------------------------------------------
+// super
+// --------------------------------------------------------------------------
+ at implementation NSStringArray
+- (void)useSuperMethod {
+  int *ip;
+  ip = super.lastObject; // expected-error{{from incompatible type 'NSString *'}}
+  ip = [super objectAtIndexedSubscript:0]; // expected-error{{from incompatible type 'NSString *'}}
+}
+
++ (void)useSuperMethod {
+  int *ip;
+  ip = super.array; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+  ip = [super array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+}
+ at end
+
+// --------------------------------------------------------------------------
+// Template instantiation
+// --------------------------------------------------------------------------
+template<typename K, typename V>
+struct NSMutableDictionaryOf {
+  typedef NSMutableDictionary<K, V> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}}
+};
+
+template<typename ...Args>
+struct VariadicNSMutableDictionaryOf {
+  typedef NSMutableDictionary<Args...> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}}
+  // expected-error at -1{{too many type arguments for class 'NSMutableDictionary' (have 3, expected 2)}}
+  // expected-error at -2{{too few type arguments for class 'NSMutableDictionary' (have 1, expected 2)}}
+};
+
+void testInstantiation() {
+  int *ip;
+
+  typedef NSMutableDictionaryOf<NSString *, NSObject *>::type Dict1;
+  Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}}
+
+  typedef NSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}}
+}
+
+void testVariadicInstantiation() {
+  int *ip;
+
+  typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *>::type Dict1;
+  Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}}
+
+  typedef VariadicNSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}}
+
+  typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *, NSObject *>::type Dict3; // expected-note{{in instantiation of template}}
+
+  typedef VariadicNSMutableDictionaryOf<NSString *>::type Dict3; // expected-note{{in instantiation of template}}
+}
+
+// --------------------------------------------------------------------------
+// Parameterized classes are not templates
+// --------------------------------------------------------------------------
+template<template<typename T, typename U> class TT>
+struct AcceptsTemplateTemplate { };
+
+typedef AcceptsTemplateTemplate<NSMutableDictionary> TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}}
+
+template<typename T>
+struct DependentTemplate {
+  typedef typename T::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
+};
+
+struct NSMutableDictionaryBuilder {
+  typedef NSMutableDictionary apply;
+};
+
+typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}}
+
+template<typename K, typename V>
+struct NonDependentTemplate {
+  typedef NSMutableDictionaryBuilder::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
+  // expected-error at -1{{expected member name or }}
+};
+
+// However, one can use an alias template to turn a parameterized
+// class into a template.
+template<typename K, typename V>
+using NSMutableDictionaryAlias = NSMutableDictionary<K, V>;
+
+typedef AcceptsTemplateTemplate<NSMutableDictionaryAlias> TemplateTemplateAlias1; // okay
+
+

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Mon Jul  6 22:58:14 2015
@@ -916,6 +916,18 @@ bool CursorVisitor::VisitTemplateTemplat
   return false;
 }
 
+bool CursorVisitor::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
+  // Visit the bound, if it's explicit.
+  if (D->hasExplicitBound()) {
+    if (auto TInfo = D->getTypeSourceInfo()) {
+      if (Visit(TInfo->getTypeLoc()))
+        return true;
+    }
+  }
+
+  return false;
+}
+
 bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
   if (TypeSourceInfo *TSInfo = ND->getReturnTypeSourceInfo())
     if (Visit(TSInfo->getTypeLoc()))
@@ -1091,14 +1103,6 @@ bool CursorVisitor::VisitObjCTypeParamLi
     // Visit the type parameter.
     if (Visit(MakeCXCursor(typeParam, TU, RegionOfInterest)))
       return true;
-
-    // Visit the bound, if it's explicit.
-    if (typeParam->hasExplicitBound()) {
-      if (auto TInfo = typeParam->getTypeSourceInfo()) {
-        if (Visit(TInfo->getTypeLoc()))
-          return true;
-      }
-    }
   }
 
   return false;

Modified: cfe/trunk/tools/libclang/CursorVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CursorVisitor.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CursorVisitor.h (original)
+++ cfe/trunk/tools/libclang/CursorVisitor.h Mon Jul  6 22:58:14 2015
@@ -217,6 +217,7 @@ public:
   bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
   bool VisitClassTemplateDecl(ClassTemplateDecl *D);
   bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+  bool VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
   bool VisitObjCMethodDecl(ObjCMethodDecl *ND);
   bool VisitObjCContainerDecl(ObjCContainerDecl *D);
   bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);





More information about the cfe-commits mailing list