r241543 - Substitute type arguments into uses of Objective-C interface members.

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


Author: dgregor
Date: Mon Jul  6 22:57:53 2015
New Revision: 241543

URL: http://llvm.org/viewvc/llvm-project?rev=241543&view=rev
Log:
Substitute type arguments into uses of Objective-C interface members.

When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.

This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.

Example:

  @interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
  - (T)firstObject;
  @end

  void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
    [stringSet firstObject]; // produces NSString*
    [anySet firstObject]; // produces id<NSCopying> (the bound)
  }

When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:

  - In covariant positions, such as method return types, replace type
    parameters with “id” or “Class” (the latter only when the type
    parameter bound is “Class” or qualified class, e.g,
    “Class<NSCopying>”)
  - In other positions (e.g., parameter types), replace type
    parameters with their type bounds.
  - When a specialized Objective-C object or object pointer type
    contains a type parameter in its type arguments (e.g.,
    NSArray<T>*, but not NSArray<NSString *> *), replace the entire
    object/object pointer type with its unspecialized version (e.g.,
    NSArray *).

Added:
    cfe/trunk/test/CodeGenObjC/parameterized_classes.m
    cfe/trunk/test/SemaObjC/parameterized_classes_subst.m
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h
Modified:
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/include/clang/AST/ExprObjC.h
    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/Sema.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclObjC.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypeLoc.cpp
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseInit.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprMember.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
    cfe/trunk/lib/Sema/SemaPseudoObject.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/PCH/objc_parameterized_classes.m
    cfe/trunk/test/SemaObjC/parameterized_classes.m
    cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Mon Jul  6 22:57:53 2015
@@ -337,6 +337,10 @@ public:
     return getReturnType().getNonLValueExprType(getASTContext());
   }
 
+  /// Determine the type of an expression that sends a message to this
+  /// function with the given receiver type.
+  QualType getSendResultType(QualType receiverType) const;
+
   TypeSourceInfo *getReturnTypeSourceInfo() const { return ReturnTInfo; }
   void setReturnTypeSourceInfo(TypeSourceInfo *TInfo) { ReturnTInfo = TInfo; }
 
@@ -516,19 +520,23 @@ public:
 class ObjCTypeParamDecl : public TypedefNameDecl {
   void anchor() override;
 
+  /// Index of this type parameter in the type parameter list.
+  unsigned Index : 16;
+
   // The location of the ':', which will be valid when the bound was
   // explicitly specified.
   SourceLocation ColonLoc;
 
-  ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc,
+  ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc, unsigned index,
                     SourceLocation nameLoc, IdentifierInfo *name,
                     SourceLocation colonLoc, TypeSourceInfo *boundInfo)
     : TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name,
                       boundInfo),
-      ColonLoc(colonLoc) { }
+      Index(index), ColonLoc(colonLoc) { }
 
 public:
   static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc,
+                                   unsigned index,
                                    SourceLocation nameLoc,
                                    IdentifierInfo *name,
                                    SourceLocation colonLoc,
@@ -537,6 +545,9 @@ public:
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
+  /// Retrieve the index into its type parameter list.
+  unsigned getIndex() const { return Index; }
+
   /// Whether this type parameter has an explicitly-written type bound, e.g.,
   /// "T : NSView".
   bool hasExplicitBound() const { return ColonLoc.isValid(); }
@@ -617,6 +628,10 @@ public:
   SourceLocation getLAngleLoc() const { return Brackets.getBegin(); }
   SourceLocation getRAngleLoc() const { return Brackets.getEnd(); }
   SourceRange getSourceRange() const { return Brackets; }
+
+  /// Gather the default set of type arguments to be substituted for
+  /// these type parameters when dealing with an unspecialized type.
+  void gatherDefaultTypeArgs(SmallVectorImpl<QualType> &typeArgs) const;
 };
 
 /// ObjCContainerDecl - Represents a container for method declarations.
@@ -1583,6 +1598,10 @@ public:
   void setSynthesize(bool synth) { Synthesized = synth; }
   bool getSynthesize() const { return Synthesized; }
 
+  /// Retrieve the type of this instance variable when viewed as a member of a
+  /// specific object type.
+  QualType getUsageType(QualType objectType) const;
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == ObjCIvar; }
@@ -2424,6 +2443,10 @@ public:
     DeclTypeSourceInfo = TSI; 
   }
 
+  /// Retrieve the type when this property is used with a specific base object
+  /// type.
+  QualType getUsageType(QualType objectType) const;
+
   PropertyAttributeKind getPropertyAttributes() const {
     return PropertyAttributeKind(PropertyAttributes);
   }

Modified: cfe/trunk/include/clang/AST/ExprObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprObjC.h?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprObjC.h (original)
+++ cfe/trunk/include/clang/AST/ExprObjC.h Mon Jul  6 22:57:53 2015
@@ -687,40 +687,7 @@ public:
   QualType getSuperReceiverType() const { 
     return QualType(Receiver.get<const Type*>(), 0); 
   }
-  QualType getGetterResultType() const {
-    QualType ResultType;
-    if (isExplicitProperty()) {
-      const ObjCPropertyDecl *PDecl = getExplicitProperty();
-      if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
-        ResultType = Getter->getReturnType();
-      else
-        ResultType = PDecl->getType();
-    } else {
-      const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
-      if (Getter)
-        ResultType = Getter->getReturnType(); // with reference!
-    }
-    return ResultType;
-  }
 
-  QualType getSetterArgType() const {
-    QualType ArgType;
-    if (isImplicitProperty()) {
-      const ObjCMethodDecl *Setter = getImplicitPropertySetter();
-      ObjCMethodDecl::param_const_iterator P = Setter->param_begin(); 
-      ArgType = (*P)->getType();
-    } else {
-      if (ObjCPropertyDecl *PDecl = getExplicitProperty())
-        if (const ObjCMethodDecl *Setter = PDecl->getSetterMethodDecl()) {
-          ObjCMethodDecl::param_const_iterator P = Setter->param_begin(); 
-          ArgType = (*P)->getType();
-        }
-      if (ArgType.isNull())
-        ArgType = getType();
-    }
-    return ArgType;
-  }
-  
   ObjCInterfaceDecl *getClassReceiver() const {
     return Receiver.get<ObjCInterfaceDecl*>();
   }
@@ -728,6 +695,9 @@ public:
   bool isSuperReceiver() const { return Receiver.is<const Type*>(); }
   bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); }
 
+  /// Determine the type of the base, regardless of the kind of receiver.
+  QualType getReceiverType(const ASTContext &ctx) const;
+
   SourceLocation getLocStart() const LLVM_READONLY {
     return isObjectReceiver() ? getBase()->getLocStart() :getReceiverLocation();
   }

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Jul  6 22:57:53 2015
@@ -533,6 +533,24 @@ struct SplitQualType {
   }
 };
 
+/// The kind of type we are substituting Objective-C type arguments into.
+///
+/// The kind of substitution affects the replacement of type parameters when
+/// no concrete type information is provided, e.g., when dealing with an
+/// unspecialized type.
+enum class ObjCSubstitutionContext {
+  /// An ordinary type.
+  Ordinary,
+  /// The result type of a method or function.
+  Result,
+  /// The parameter type of a method or function.
+  Parameter,
+  /// The type of a property.
+  Property,
+  /// The superclass of a type.
+  Superclass,
+};
+
 /// QualType - For efficiency, we don't store CV-qualified types as nodes on
 /// their own: instead each reference to a type stores the qualifiers.  This
 /// greatly reduces the number of nodes we need to allocate for types (for
@@ -994,6 +1012,48 @@ public:
   ///   type other than void.
   bool isCForbiddenLValueType() const;
 
+  /// Substitute type arguments for the Objective-C type parameters used in the
+  /// subject type.
+  ///
+  /// \param ctx ASTContext in which the type exists.
+  ///
+  /// \param typeArgs The type arguments that will be substituted for the
+  /// Objective-C type parameters in the subject type, which are generally
+  /// computed via \c Type::getObjCSubstitutions. If empty, the type
+  /// parameters will be replaced with their bounds or id/Class, as appropriate
+  /// for the context.
+  ///
+  /// \param context The context in which the subject type was written.
+  ///
+  /// \returns the resulting type.
+  QualType substObjCTypeArgs(ASTContext &ctx,
+                             ArrayRef<QualType> typeArgs,
+                             ObjCSubstitutionContext context) const;
+
+  /// Substitute type arguments from an object type for the Objective-C type
+  /// parameters used in the subject type.
+  ///
+  /// This operation combines the computation of type arguments for
+  /// substitution (\c Type::getObjCSubstitutions) with the actual process of
+  /// substitution (\c QualType::substObjCTypeArgs) for the convenience of
+  /// callers that need to perform a single substitution in isolation.
+  ///
+  /// \param objectType The type of the object whose member type we're
+  /// substituting into. For example, this might be the receiver of a message
+  /// or the base of a property access.
+  ///
+  /// \param dc The declaration context from which the subject type was
+  /// retrieved, which indicates (for example) which type parameters should
+  /// be substituted.
+  ///
+  /// \param context The context in which the subject type was written.
+  ///
+  /// \returns the subject type after replacing all of the Objective-C type
+  /// parameters with their corresponding arguments.
+  QualType substObjCMemberType(QualType objectType,
+                               const DeclContext *dc,
+                               ObjCSubstitutionContext context) const;
+
 private:
   // These methods are implemented in a separate translation unit;
   // "static"-ize them to avoid creating temporary QualTypes in the
@@ -1702,6 +1762,7 @@ public:
   /// NOTE: getAs*ArrayType are methods on ASTContext.
   const RecordType *getAsUnionType() const;
   const ComplexType *getAsComplexIntegerType() const; // GCC complex int type.
+  const ObjCObjectType *getAsObjCInterfaceType() const;
   // The following is a convenience method that returns an ObjCObjectPointerType
   // for object declared using an interface.
   const ObjCObjectPointerType *getAsObjCInterfacePointerType() const;
@@ -1837,6 +1898,24 @@ public:
   /// pointer type.
   bool canHaveNullability() const;
 
+  /// Retrieve the set of substitutions required when accessing a member
+  /// of the Objective-C receiver type that is declared in the given context.
+  ///
+  /// \c *this is the type of the object we're operating on, e.g., the
+  /// receiver for a message send or the base of a property access, and is
+  /// expected to be of some object or object pointer type.
+  ///
+  /// \param dc The declaration context for which we are building up a
+  /// substitution mapping, which should be an Objective-C class, extension,
+  /// category, or method within.
+  ///
+  /// \returns an array of type arguments that can be substituted for
+  /// the type parameters of the given declaration context in any type described
+  /// within that context, or an empty optional to indicate that no
+  /// substitution is required.
+  Optional<ArrayRef<QualType>>
+  getObjCSubstitutions(const DeclContext *dc) const;
+
   const char *getTypeClassName() const;
 
   QualType getCanonicalTypeInternal() const {
@@ -4417,6 +4496,10 @@ class ObjCObjectType : public Type {
   /// Either a BuiltinType or an InterfaceType or sugar for either.
   QualType BaseType;
 
+  /// Cached superclass type.
+  mutable llvm::PointerIntPair<const ObjCObjectType *, 1, bool>
+    CachedSuperClassType;
+
   ObjCProtocolDecl * const *getProtocolStorage() const {
     return const_cast<ObjCObjectType*>(this)->getProtocolStorage();
   }
@@ -4441,6 +4524,8 @@ protected:
     ObjCObjectTypeBits.NumTypeArgs = 0;
   }
 
+  void computeSuperClassTypeSlow() const;
+
 public:
   /// getBaseType - Gets the base type of this object type.  This is
   /// always (possibly sugar for) one of:
@@ -4518,6 +4603,20 @@ public:
     return qual_begin()[I];
   }
 
+  /// Retrieve the type of the superclass of this object type.
+  ///
+  /// This operation substitutes any type arguments into the
+  /// superclass of the current class type, potentially producing a
+  /// specialization of the superclass type. Produces a null type if
+  /// there is no superclass.
+  QualType getSuperClassType() const {
+    if (!CachedSuperClassType.getInt())
+      computeSuperClassTypeSlow();
+
+    assert(CachedSuperClassType.getInt() && "Superclass not set?");
+    return QualType(CachedSuperClassType.getPointer(), 0);
+  }
+
   bool isSugared() const { return false; }
   QualType desugar() const { return QualType(this, 0); }
 
@@ -4764,6 +4863,14 @@ public:
   bool isSugared() const { return false; }
   QualType desugar() const { return QualType(this, 0); }
 
+  /// Retrieve the type of the superclass of this object pointer type.
+  ///
+  /// This operation substitutes any type arguments into the
+  /// superclass of the current class type, potentially producing a
+  /// pointer to a specialization of the superclass type. Produces a
+  /// null type if there is no superclass.
+  QualType getSuperClassType() const;
+
   void Profile(llvm::FoldingSetNodeID &ID) {
     Profile(ID, getPointeeType());
   }

Modified: cfe/trunk/include/clang/AST/TypeLoc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeLoc.h?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TypeLoc.h (original)
+++ cfe/trunk/include/clang/AST/TypeLoc.h Mon Jul  6 22:57:53 2015
@@ -185,6 +185,10 @@ public:
     return !(LHS == RHS);
   }
 
+  /// Find the location of the nullability specifier (__nonnull,
+  /// __nullable, or __null_unspecifier), if there is one.
+  SourceLocation findNullabilityLoc() const;
+
 private:
   static bool isKind(const TypeLoc&) {
     return true;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul  6 22:57:53 2015
@@ -7743,6 +7743,13 @@ def warn_nullability_missing : Warning<
   "%select{pointer|block pointer|member pointer}0 is missing a nullability "
   "type specifier (_Nonnull, _Nullable, or _Null_unspecified)">,
   InGroup<NullabilityCompleteness>;
+
+def err_type_arg_explicit_nullability : Error<
+  "type argument %0 cannot explicitly specify nullability">;
+
+def err_type_param_bound_explicit_nullability : Error<
+  "type parameter %0 bound %1 cannot explicitly specify nullability">;
+
 }
 
 let CategoryName = "Generics Issue" in {

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul  6 22:57:53 2015
@@ -1271,6 +1271,16 @@ private:
   bool ParseObjCProtocolQualifiers(DeclSpec &DS);
   void ParseObjCTypeArgsOrProtocolQualifiers(DeclSpec &DS,
                                              bool warnOnIncompleteProtocols);
+
+  /// Parse either Objective-C type arguments or protocol qualifiers; if the
+  /// former, also parse protocol qualifiers afterward.
+  void ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS);
+
+  /// Parse Objective-C type arguments and protocol qualifiers, extending the
+  /// current type with the parsed result.
+  TypeResult ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
+                                                    ParsedType type);
+
   void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
                                   Decl *CDecl);
   DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc,

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul  6 22:57:53 2015
@@ -2187,6 +2187,7 @@ public:
   void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
                                   QualType FromType, QualType ToType);
 
+  void maybeExtendBlockObject(ExprResult &E);
   CastKind PrepareCastToObjCObjectPointer(ExprResult &E);
   bool CheckPointerConversion(Expr *From, QualType ToType,
                               CastKind &Kind,
@@ -7088,7 +7089,8 @@ public:
   };
   ObjCContainerKind getObjCContainerKind() const;
 
-  DeclResult actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
+  DeclResult actOnObjCTypeParam(Scope *S, unsigned index,
+                                IdentifierInfo *paramName,
                                 SourceLocation paramLoc,
                                 SourceLocation colonLoc,
                                 ParsedType typeBound);

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Jul  6 22:57:53 2015
@@ -6893,9 +6893,13 @@ QualType ASTContext::areCommonBaseCompat
   const ObjCInterfaceDecl* RDecl = RHS->getInterface();
   if (!LDecl || !RDecl || (declaresSameEntity(LDecl, RDecl)))
     return QualType();
-  
-  do {
-    LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl));
+
+  while (!declaresSameEntity(LHS->getInterface(), RDecl)) {
+    // Strip protocols from the left-hand side.
+    if (LHS->getNumProtocols() > 0)
+      LHS = getObjCObjectType(LHS->getBaseType(), LHS->getTypeArgsAsWritten(),
+                              { })->castAs<ObjCObjectType>();
+
     if (canAssignObjCInterfaces(LHS, RHS)) {
       SmallVector<ObjCProtocolDecl *, 8> Protocols;
       getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols);
@@ -6906,7 +6910,13 @@ QualType ASTContext::areCommonBaseCompat
       Result = getObjCObjectPointerType(Result);
       return Result;
     }
-  } while ((LDecl = LDecl->getSuperClass()));
+
+    QualType LHSSuperType = LHS->getSuperClassType();
+    if (LHSSuperType.isNull())
+      break;
+
+    LHS = LHSSuperType->castAs<ObjCObjectType>();
+  }
     
   return QualType();
 }
@@ -6918,21 +6928,15 @@ bool ASTContext::canAssignObjCInterfaces
 
   // Verify that the base decls are compatible: the RHS must be a subclass of
   // the LHS.
-  if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface()))
+  ObjCInterfaceDecl *LHSInterface = LHS->getInterface();
+  bool IsSuperClass = LHSInterface->isSuperClassOf(RHS->getInterface());
+  if (!IsSuperClass)
     return false;
 
-  // RHS must have a superset of the protocols in the LHS.  If the LHS is not
-  // protocol qualified at all, then we are good.
-  if (LHS->getNumProtocols() == 0)
-    return true;
-
-  // Okay, we know the LHS has protocol qualifiers. But RHS may or may not.
-  // More detailed analysis is required.
-  // OK, if LHS is same or a superclass of RHS *and*
-  // this LHS, or as RHS's super class is assignment compatible with LHS.
-  bool IsSuperClass =
-    LHS->getInterface()->isSuperClassOf(RHS->getInterface());
-  if (IsSuperClass) {
+  // If the LHS has protocol qualifiers, determine whether all of them are
+  // satisfied by the RHS (i.e., the RHS has a superset of the protocols in the
+  // LHS).
+  if (LHS->getNumProtocols() > 0) {
     // OK if conversion of LHS to SuperClass results in narrowing of types
     // ; i.e., SuperClass may implement at least one of the protocols
     // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok.
@@ -6957,9 +6961,28 @@ bool ASTContext::canAssignObjCInterfaces
       if (!SuperImplementsProtocol)
         return false;
     }
-    return true;
   }
-  return false;
+
+  // If the LHS is specialized, we may need to check type arguments.
+  if (LHS->isSpecialized()) {
+    // Follow the superclass chain until we've matched the LHS class in the
+    // hierarchy. This substitutes type arguments through.
+    const ObjCObjectType *RHSSuper = RHS;
+    while (!declaresSameEntity(RHSSuper->getInterface(), LHSInterface))
+      RHSSuper = RHSSuper->getSuperClassType()->castAs<ObjCObjectType>();
+
+    // If the RHS is specializd, compare type arguments.
+    if (RHSSuper->isSpecialized()) {
+      ArrayRef<QualType> LHSTypeArgs = LHS->getTypeArgs();
+      ArrayRef<QualType> RHSTypeArgs = RHSSuper->getTypeArgs();
+      for (unsigned i = 0, n = LHSTypeArgs.size(); i != n; ++i) {
+        if (!hasSameType(LHSTypeArgs[i], RHSTypeArgs[i]))
+          return false;
+      }
+    }
+  }
+
+  return true;
 }
 
 bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Jul  6 22:57:53 2015
@@ -1845,7 +1845,7 @@ QualType ASTNodeImporter::VisitObjCObjec
     return QualType();
 
   SmallVector<QualType, 4> TypeArgs;
-  for (auto TypeArg : T->getTypeArgs()) {
+  for (auto TypeArg : T->getTypeArgsAsWritten()) {
     QualType ImportedTypeArg = Importer.Import(TypeArg);
     if (ImportedTypeArg.isNull())
       return QualType();
@@ -3452,6 +3452,7 @@ Decl *ASTNodeImporter::VisitObjCTypePara
 
   ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create(
                                 Importer.getToContext(), DC,
+                                D->getIndex(),
                                 Importer.Import(D->getLocation()),
                                 Name.getAsIdentifierInfo(),
                                 Importer.Import(D->getColonLoc()),

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Mon Jul  6 22:57:53 2015
@@ -1013,6 +1013,14 @@ SourceRange ObjCMethodDecl::getReturnTyp
   return SourceRange();
 }
 
+QualType ObjCMethodDecl::getSendResultType(QualType receiverType) const {
+  // FIXME: Handle related result types here.
+
+  return getReturnType().getNonLValueExprType(getASTContext())
+           .substObjCMemberType(receiverType, getDeclContext(),
+                                ObjCSubstitutionContext::Result);
+}
+
 static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
                                             const ObjCMethodDecl *Method,
                                SmallVectorImpl<const ObjCMethodDecl *> &Methods,
@@ -1190,17 +1198,18 @@ ObjCMethodDecl::findPropertyDecl(bool Ch
 void ObjCTypeParamDecl::anchor() { }
 
 ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc,
+                                             unsigned index,
                                              SourceLocation nameLoc,
                                              IdentifierInfo *name,
                                              SourceLocation colonLoc,
                                              TypeSourceInfo *boundInfo) {
-  return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, nameLoc, name, colonLoc,
+  return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, index, nameLoc, name, colonLoc,
                                          boundInfo);
 }
 
 ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
                                                          unsigned ID) {
-  return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, SourceLocation(),
+  return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, 0, SourceLocation(),
                                          nullptr, SourceLocation(), nullptr);
 }
 
@@ -1239,6 +1248,13 @@ ObjCTypeParamList *ObjCTypeParamList::cr
   return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc);
 }
 
+void ObjCTypeParamList::gatherDefaultTypeArgs(
+       SmallVectorImpl<QualType> &typeArgs) const {
+  typeArgs.reserve(size());
+  for (auto typeParam : *this)
+    typeArgs.push_back(typeParam->getUnderlyingType());
+}
+
 //===----------------------------------------------------------------------===//
 // ObjCInterfaceDecl
 //===----------------------------------------------------------------------===//
@@ -1606,6 +1622,11 @@ const ObjCInterfaceDecl *ObjCIvarDecl::g
   }
 }
 
+QualType ObjCIvarDecl::getUsageType(QualType objectType) const {
+  return getType().substObjCMemberType(objectType, getDeclContext(),
+                                       ObjCSubstitutionContext::Property);
+}
+
 //===----------------------------------------------------------------------===//
 // ObjCAtDefsFieldDecl
 //===----------------------------------------------------------------------===//
@@ -2012,6 +2033,11 @@ ObjCPropertyDecl *ObjCPropertyDecl::Crea
                                       QualType(), nullptr, None);
 }
 
+QualType ObjCPropertyDecl::getUsageType(QualType objectType) const {
+  return DeclType.substObjCMemberType(objectType, getDeclContext(),
+                                      ObjCSubstitutionContext::Property);
+}
+
 //===----------------------------------------------------------------------===//
 // ObjCPropertyImplDecl
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Mon Jul  6 22:57:53 2015
@@ -3748,6 +3748,16 @@ ObjCInterfaceDecl *ObjCMessageExpr::getR
   return nullptr;
 }
 
+QualType ObjCPropertyRefExpr::getReceiverType(const ASTContext &ctx) const {
+  if (isClassReceiver())
+    return ctx.getObjCInterfaceType(getClassReceiver());
+
+  if (isSuperReceiver())
+    return getSuperReceiverType();
+
+  return getBase()->getType();
+}
+
 StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
   switch (getBridgeKind()) {
   case OBC_Bridge:

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Jul  6 22:57:53 2015
@@ -491,10 +491,13 @@ bool ObjCObjectType::isSpecialized() con
   if (ObjCObjectTypeBits.NumTypeArgs > 0)
     return true;
 
-  if (!qual_empty()) {
-    // Otherwise, check whether the base type is specialized.
-    if (auto objcObject = getBaseType()->getAs<ObjCObjectType>())
-      return objcObject->isSpecialized();
+  // Otherwise, check whether the base type is specialized.
+  if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) {
+    // Terminate when we reach an interface type.
+    if (isa<ObjCInterfaceType>(objcObject))
+      return false;
+
+    return objcObject->isSpecialized();
   }
 
   // Not specialized.
@@ -506,16 +509,765 @@ ArrayRef<QualType> ObjCObjectType::getTy
   if (isSpecializedAsWritten())
     return getTypeArgsAsWritten();
 
-  if (!qual_empty()) {
-    // Look at the base type, which might have type arguments.
-    if (auto objcObject = getBaseType()->getAs<ObjCObjectType>())
-      return objcObject->getTypeArgs();
+  // Look at the base type, which might have type arguments.
+  if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) {
+    // Terminate when we reach an interface type.
+    if (isa<ObjCInterfaceType>(objcObject))
+      return { };
+
+    return objcObject->getTypeArgs();
   }
 
   // No type arguments.
   return { };
 }
 
+namespace {
+
+/// Perform a simple type transformation that does not change the
+/// semantics of the type.
+template<typename F>
+QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) {
+  struct Visitor : public TypeVisitor<Visitor, QualType> {
+    ASTContext &Ctx;
+    F &&TheFunc;
+
+    QualType recurse(QualType type) {
+      return simpleTransform(Ctx, type, std::move(TheFunc));
+    }
+
+  public:
+    Visitor(ASTContext &ctx, F &&f) : Ctx(ctx), TheFunc(std::move(f)) { }
+
+    // None of the clients of this transformation can occur where
+    // there are dependent types, so skip dependent types.
+#define TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) \
+    QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
+#include "clang/AST/TypeNodes.def"
+
+#define TRIVIAL_TYPE_CLASS(Class) \
+    QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
+
+    TRIVIAL_TYPE_CLASS(Builtin)
+
+    QualType VisitComplexType(const ComplexType *T) { 
+      QualType elementType = recurse(T->getElementType());
+      if (elementType.isNull())
+        return QualType();
+
+      if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getComplexType(elementType);
+    }
+
+    QualType VisitPointerType(const PointerType *T) {
+      QualType pointeeType = recurse(T->getPointeeType());
+      if (pointeeType.isNull())
+        return QualType();
+
+      if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getPointerType(pointeeType);
+    }
+
+    QualType VisitBlockPointerType(const BlockPointerType *T) {
+      QualType pointeeType = recurse(T->getPointeeType());
+      if (pointeeType.isNull())
+        return QualType();
+
+      if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getBlockPointerType(pointeeType);
+    }
+
+    QualType VisitLValueReferenceType(const LValueReferenceType *T) {
+      QualType pointeeType = recurse(T->getPointeeTypeAsWritten());
+      if (pointeeType.isNull())
+        return QualType();
+
+      if (pointeeType.getAsOpaquePtr() 
+            == T->getPointeeTypeAsWritten().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getLValueReferenceType(pointeeType, T->isSpelledAsLValue());
+    }
+
+    QualType VisitRValueReferenceType(const RValueReferenceType *T) {
+      QualType pointeeType = recurse(T->getPointeeTypeAsWritten());
+      if (pointeeType.isNull())
+        return QualType();
+
+      if (pointeeType.getAsOpaquePtr() 
+            == T->getPointeeTypeAsWritten().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getRValueReferenceType(pointeeType);
+    }
+
+    QualType VisitMemberPointerType(const MemberPointerType *T) {
+      QualType pointeeType = recurse(T->getPointeeType());
+      if (pointeeType.isNull())
+        return QualType();
+
+      if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getMemberPointerType(pointeeType, T->getClass());      
+    }
+
+    QualType VisitConstantArrayType(const ConstantArrayType *T) {
+      QualType elementType = recurse(T->getElementType());
+      if (elementType.isNull())
+        return QualType();
+
+      if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getConstantArrayType(elementType, T->getSize(),
+                                      T->getSizeModifier(),
+                                      T->getIndexTypeCVRQualifiers());
+    }
+
+    QualType VisitVariableArrayType(const VariableArrayType *T) {
+      QualType elementType = recurse(T->getElementType());
+      if (elementType.isNull())
+        return QualType();
+
+      if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getVariableArrayType(elementType, T->getSizeExpr(),
+                                      T->getSizeModifier(),
+                                      T->getIndexTypeCVRQualifiers(),
+                                      T->getBracketsRange());
+    }
+
+    QualType VisitIncompleteArrayType(const IncompleteArrayType *T) {
+      QualType elementType = recurse(T->getElementType());
+      if (elementType.isNull())
+        return QualType();
+
+      if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getIncompleteArrayType(elementType, T->getSizeModifier(),
+                                        T->getIndexTypeCVRQualifiers());
+    }
+
+    QualType VisitVectorType(const VectorType *T) { 
+      QualType elementType = recurse(T->getElementType());
+      if (elementType.isNull())
+        return QualType();
+
+      if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getVectorType(elementType, T->getNumElements(), 
+                               T->getVectorKind());
+    }
+
+    QualType VisitExtVectorType(const ExtVectorType *T) { 
+      QualType elementType = recurse(T->getElementType());
+      if (elementType.isNull())
+        return QualType();
+
+      if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getExtVectorType(elementType, T->getNumElements());
+    }
+
+    QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T) { 
+      QualType returnType = recurse(T->getReturnType());
+      if (returnType.isNull())
+        return QualType();
+
+      if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getFunctionNoProtoType(returnType, T->getExtInfo());
+    }
+
+    QualType VisitFunctionProtoType(const FunctionProtoType *T) { 
+      QualType returnType = recurse(T->getReturnType());
+      if (returnType.isNull())
+        return QualType();
+
+      // Transform parameter types.
+      SmallVector<QualType, 4> paramTypes;
+      bool paramChanged = false;
+      for (auto paramType : T->getParamTypes()) {
+        QualType newParamType = recurse(paramType);
+        if (newParamType.isNull())
+          return QualType();
+
+        if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr())
+          paramChanged = true;
+
+        paramTypes.push_back(newParamType);
+      }
+
+      // Transform extended info.
+      FunctionProtoType::ExtProtoInfo info = T->getExtProtoInfo();
+      bool exceptionChanged = false;
+      if (info.ExceptionSpec.Type == EST_Dynamic) {
+        SmallVector<QualType, 4> exceptionTypes;
+        for (auto exceptionType : info.ExceptionSpec.Exceptions) {
+          QualType newExceptionType = recurse(exceptionType);
+          if (newExceptionType.isNull())
+            return QualType();
+          
+          if (newExceptionType.getAsOpaquePtr() 
+                != exceptionType.getAsOpaquePtr())
+            exceptionChanged = true;
+
+          exceptionTypes.push_back(newExceptionType);
+        }
+
+        if (exceptionChanged) {
+          unsigned size = sizeof(QualType) * exceptionTypes.size();
+          void *mem = Ctx.Allocate(size, llvm::alignOf<QualType>());
+          memcpy(mem, exceptionTypes.data(), size);
+          info.ExceptionSpec.Exceptions
+            = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size());
+        }
+      }
+
+      if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr() &&
+          !paramChanged && !exceptionChanged)
+        return QualType(T, 0);
+
+      return Ctx.getFunctionType(returnType, paramTypes, info);
+    }
+
+    QualType VisitParenType(const ParenType *T) { 
+      QualType innerType = recurse(T->getInnerType());
+      if (innerType.isNull())
+        return QualType();
+
+      if (innerType.getAsOpaquePtr() == T->getInnerType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getParenType(innerType);
+    }
+
+    TRIVIAL_TYPE_CLASS(Typedef)
+
+    QualType VisitAdjustedType(const AdjustedType *T) { 
+      QualType originalType = recurse(T->getOriginalType());
+      if (originalType.isNull())
+        return QualType();
+
+      QualType adjustedType = recurse(T->getAdjustedType());
+      if (adjustedType.isNull())
+        return QualType();
+
+      if (originalType.getAsOpaquePtr() 
+            == T->getOriginalType().getAsOpaquePtr() &&
+          adjustedType.getAsOpaquePtr() == T->getAdjustedType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getAdjustedType(originalType, adjustedType);
+    }
+    
+    QualType VisitDecayedType(const DecayedType *T) { 
+      QualType originalType = recurse(T->getOriginalType());
+      if (originalType.isNull())
+        return QualType();
+
+      if (originalType.getAsOpaquePtr() 
+            == T->getOriginalType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getDecayedType(originalType);
+    }
+
+    TRIVIAL_TYPE_CLASS(TypeOfExpr)
+    TRIVIAL_TYPE_CLASS(TypeOf)
+    TRIVIAL_TYPE_CLASS(Decltype)
+    TRIVIAL_TYPE_CLASS(UnaryTransform)
+    TRIVIAL_TYPE_CLASS(Record)
+    TRIVIAL_TYPE_CLASS(Enum)
+
+    // FIXME: Non-trivial to implement, but important for C++
+    TRIVIAL_TYPE_CLASS(Elaborated)
+
+    QualType VisitAttributedType(const AttributedType *T) { 
+      QualType modifiedType = recurse(T->getModifiedType());
+      if (modifiedType.isNull())
+        return QualType();
+
+      QualType equivalentType = recurse(T->getEquivalentType());
+      if (equivalentType.isNull())
+        return QualType();
+
+      if (modifiedType.getAsOpaquePtr() 
+            == T->getModifiedType().getAsOpaquePtr() &&
+          equivalentType.getAsOpaquePtr() 
+            == T->getEquivalentType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getAttributedType(T->getAttrKind(), modifiedType, 
+                                   equivalentType);
+    }
+
+    QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
+      QualType replacementType = recurse(T->getReplacementType());
+      if (replacementType.isNull())
+        return QualType();
+
+      if (replacementType.getAsOpaquePtr() 
+            == T->getReplacementType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(),
+                                              replacementType);
+    }
+
+    // FIXME: Non-trivial to implement, but important for C++
+    TRIVIAL_TYPE_CLASS(TemplateSpecialization)
+
+    QualType VisitAutoType(const AutoType *T) {
+      if (!T->isDeduced())
+        return QualType(T, 0);
+
+      QualType deducedType = recurse(T->getDeducedType());
+      if (deducedType.isNull())
+        return QualType();
+
+      if (deducedType.getAsOpaquePtr() 
+            == T->getDeducedType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getAutoType(deducedType, T->isDecltypeAuto(),
+                             T->isDependentType());
+    }
+
+    // FIXME: Non-trivial to implement, but important for C++
+    TRIVIAL_TYPE_CLASS(PackExpansion)
+
+    QualType VisitObjCObjectType(const ObjCObjectType *T) {
+      QualType baseType = recurse(T->getBaseType());
+      if (baseType.isNull())
+        return QualType();
+
+      // Transform type arguments.
+      bool typeArgChanged = false;
+      SmallVector<QualType, 4> typeArgs;
+      for (auto typeArg : T->getTypeArgsAsWritten()) {
+        QualType newTypeArg = recurse(typeArg);
+        if (newTypeArg.isNull())
+          return QualType();
+
+        if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr())
+          typeArgChanged = true;
+
+        typeArgs.push_back(newTypeArg);
+      }
+
+      if (baseType.getAsOpaquePtr() == T->getBaseType().getAsOpaquePtr() &&
+          !typeArgChanged)
+        return QualType(T, 0);
+
+      return Ctx.getObjCObjectType(baseType, typeArgs, 
+                                   llvm::makeArrayRef(T->qual_begin(),
+                                                      T->getNumProtocols()));
+    }
+
+    TRIVIAL_TYPE_CLASS(ObjCInterface)
+
+    QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
+      QualType pointeeType = recurse(T->getPointeeType());
+      if (pointeeType.isNull())
+        return QualType();
+
+      if (pointeeType.getAsOpaquePtr() 
+            == T->getPointeeType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getObjCObjectPointerType(pointeeType);
+    }
+
+    QualType VisitAtomicType(const AtomicType *T) {
+      QualType valueType = recurse(T->getValueType());
+      if (valueType.isNull())
+        return QualType();
+
+      if (valueType.getAsOpaquePtr() 
+            == T->getValueType().getAsOpaquePtr())
+        return QualType(T, 0);
+
+      return Ctx.getAtomicType(valueType);
+    }
+
+#undef TRIVIAL_TYPE_CLASS
+  };
+
+  // Transform the type. If it changed, return the transformed result.
+  QualType transformed = f(type);
+  if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr())
+    return transformed;
+
+  // Split out the qualifiers from the type.
+  SplitQualType splitType = type.split();
+
+  // Visit the type itself.
+  Visitor visitor(ctx, std::move(f));
+  QualType result = visitor.Visit(splitType.Ty);
+  if (result.isNull())
+    return result;
+
+  // Reconstruct the transformed type by applying the local qualifiers
+  // from the split type.
+  return ctx.getQualifiedType(result, splitType.Quals);
+}
+
+} // end anonymous namespace
+
+/// Substitute the given type arguments for Objective-C type
+/// parameters within the given type, recursively.
+QualType QualType::substObjCTypeArgs(
+           ASTContext &ctx,
+           ArrayRef<QualType> typeArgs,
+           ObjCSubstitutionContext context) const {
+  return simpleTransform(ctx, *this,
+                         [&](QualType type) -> QualType {
+    SplitQualType splitType = type.split();
+
+    // Replace an Objective-C type parameter reference with the corresponding
+    // type argument.
+    if (const auto *typedefTy = dyn_cast<TypedefType>(splitType.Ty)) {
+      if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(typedefTy->getDecl())) {
+        // If we have type arguments, use them.
+        if (!typeArgs.empty()) {
+          // FIXME: Introduce SubstObjCTypeParamType ?
+          QualType argType = typeArgs[typeParam->getIndex()];
+          return ctx.getQualifiedType(argType, splitType.Quals);
+        }
+
+        switch (context) {
+        case ObjCSubstitutionContext::Ordinary:
+        case ObjCSubstitutionContext::Parameter:
+        case ObjCSubstitutionContext::Superclass:
+          // Substitute the bound.
+          return ctx.getQualifiedType(typeParam->getUnderlyingType(),
+                                      splitType.Quals);
+
+        case ObjCSubstitutionContext::Result:
+        case ObjCSubstitutionContext::Property:
+          // Substitute 'id' or 'Class', as appropriate.
+
+          // If the underlying type is based on 'Class', substitute 'Class'.
+          if (typeParam->getUnderlyingType()->isObjCClassType() ||
+              typeParam->getUnderlyingType()->isObjCQualifiedClassType()) {
+            return ctx.getQualifiedType(ctx.getObjCClassType(),
+                                        splitType.Quals);
+          }
+
+          // Otherwise, substitute 'id'.
+          return ctx.getQualifiedType(ctx.getObjCIdType(), splitType.Quals);
+        }
+      }
+    }
+
+    // If we have a function type, update the context appropriately.
+    if (const auto *funcType = dyn_cast<FunctionType>(splitType.Ty)) {
+      // Substitute result type.
+      QualType returnType = funcType->getReturnType().substObjCTypeArgs(
+                              ctx,
+                              typeArgs,
+                              ObjCSubstitutionContext::Result);
+      if (returnType.isNull())
+        return QualType();
+
+      // Handle non-prototyped functions, which only substitute into the result
+      // type.
+      if (isa<FunctionNoProtoType>(funcType)) {
+        // If the return type was unchanged, do nothing.
+        if (returnType.getAsOpaquePtr()
+              == funcType->getReturnType().getAsOpaquePtr())
+          return type;
+
+        // Otherwise, build a new type.
+        return ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo());
+      }
+
+      const auto *funcProtoType = cast<FunctionProtoType>(funcType);
+
+      // Transform parameter types.
+      SmallVector<QualType, 4> paramTypes;
+      bool paramChanged = false;
+      for (auto paramType : funcProtoType->getParamTypes()) {
+        QualType newParamType = paramType.substObjCTypeArgs(
+                                  ctx,
+                                  typeArgs,
+                                  ObjCSubstitutionContext::Parameter);
+        if (newParamType.isNull())
+          return QualType();
+
+        if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr())
+          paramChanged = true;
+
+        paramTypes.push_back(newParamType);
+      }
+
+      // Transform extended info.
+      FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo();
+      bool exceptionChanged = false;
+      if (info.ExceptionSpec.Type == EST_Dynamic) {
+        SmallVector<QualType, 4> exceptionTypes;
+        for (auto exceptionType : info.ExceptionSpec.Exceptions) {
+          QualType newExceptionType = exceptionType.substObjCTypeArgs(
+                                        ctx,
+                                        typeArgs,
+                                        ObjCSubstitutionContext::Ordinary);
+          if (newExceptionType.isNull())
+            return QualType();
+
+          if (newExceptionType.getAsOpaquePtr()
+              != exceptionType.getAsOpaquePtr())
+            exceptionChanged = true;
+
+          exceptionTypes.push_back(newExceptionType);
+        }
+
+        if (exceptionChanged) {
+          unsigned size = sizeof(QualType) * exceptionTypes.size();
+          void *mem = ctx.Allocate(size, llvm::alignOf<QualType>());
+          memcpy(mem, exceptionTypes.data(), size);
+          info.ExceptionSpec.Exceptions
+            = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size());
+        }
+      }
+
+      if (returnType.getAsOpaquePtr()
+            == funcProtoType->getReturnType().getAsOpaquePtr() &&
+          !paramChanged && !exceptionChanged)
+        return type;
+
+      return ctx.getFunctionType(returnType, paramTypes, info);
+    }
+
+    // Substitute into the type arguments of a specialized Objective-C object
+    // type.
+    if (const auto *objcObjectType = dyn_cast<ObjCObjectType>(splitType.Ty)) {
+      if (objcObjectType->isSpecializedAsWritten()) {
+        SmallVector<QualType, 4> newTypeArgs;
+        bool anyChanged = false;
+        for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) {
+          QualType newTypeArg = typeArg.substObjCTypeArgs(
+                                  ctx, typeArgs,
+                                  ObjCSubstitutionContext::Ordinary);
+          if (newTypeArg.isNull())
+            return QualType();
+
+          if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) {
+            // If we're substituting based on an unspecialized context type,
+            // produce an unspecialized type.
+            ArrayRef<ObjCProtocolDecl *> protocols(
+                                           objcObjectType->qual_begin(),
+                                           objcObjectType->getNumProtocols());
+            if (typeArgs.empty() &&
+                context != ObjCSubstitutionContext::Superclass) {
+              return ctx.getObjCObjectType(objcObjectType->getBaseType(), { },
+                                           protocols);
+            }
+
+            anyChanged = true;
+          }
+
+          newTypeArgs.push_back(newTypeArg);
+        }
+
+        if (anyChanged) {
+          ArrayRef<ObjCProtocolDecl *> protocols(
+                                         objcObjectType->qual_begin(),
+                                         objcObjectType->getNumProtocols());
+          return ctx.getObjCObjectType(objcObjectType->getBaseType(),
+                                       newTypeArgs, protocols);
+        }
+      }
+
+      return type;
+    }
+
+    return type;
+  });
+}
+
+QualType QualType::substObjCMemberType(QualType objectType,
+                                       const DeclContext *dc,
+                                       ObjCSubstitutionContext context) const {
+  if (auto subs = objectType->getObjCSubstitutions(dc))
+    return substObjCTypeArgs(dc->getParentASTContext(), *subs, context);
+
+  return *this;
+}
+
+Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
+                               const DeclContext *dc) const {
+  // Look through method scopes.
+  if (auto method = dyn_cast<ObjCMethodDecl>(dc))
+    dc = method->getDeclContext();
+
+  // Find the class or category in which the type we're substituting
+  // was declared.
+  const ObjCInterfaceDecl *dcClassDecl = dyn_cast<ObjCInterfaceDecl>(dc);
+  const ObjCCategoryDecl *dcCategoryDecl = nullptr;
+  ObjCTypeParamList *dcTypeParams = nullptr;
+  if (dcClassDecl) {
+    // If the class does not have any type parameters, there's no
+    // substitution to do.
+    dcTypeParams = dcClassDecl->getTypeParamList();
+    if (!dcTypeParams)
+      return None;
+  } else {
+    // If we are in neither a class mor a category, there's no
+    // substitution to perform.
+    dcCategoryDecl = dyn_cast<ObjCCategoryDecl>(dc);
+    if (!dcCategoryDecl)
+      return None;
+
+    // If the category does not have any type parameters, there's no
+    // substitution to do.
+    dcTypeParams = dcCategoryDecl->getTypeParamList();
+    if (!dcTypeParams)
+      return None;
+
+    dcClassDecl = dcCategoryDecl->getClassInterface();
+    if (!dcClassDecl)
+      return None;
+  }
+  assert(dcTypeParams && "No substitutions to perform");
+  assert(dcClassDecl && "No class context");
+
+  // Find the underlying object type.
+  const ObjCObjectType *objectType;
+  if (const auto *objectPointerType = getAs<ObjCObjectPointerType>()) {
+    objectType = objectPointerType->getObjectType();
+  } else if (getAs<BlockPointerType>()) {
+    ASTContext &ctx = dc->getParentASTContext();
+    objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, { })
+                   ->castAs<ObjCObjectType>();;
+  } else {
+    objectType = getAs<ObjCObjectType>();
+  }
+
+  /// Extract the class from the receiver object type.
+  ObjCInterfaceDecl *curClassDecl = objectType ? objectType->getInterface()
+                                               : nullptr;
+  if (!curClassDecl) {
+    // If we don't have a context type (e.g., this is "id" or some
+    // variant thereof), substitute the bounds.
+    return llvm::ArrayRef<QualType>();
+  }
+
+  // Follow the superclass chain until we've mapped the receiver type
+  // to the same class as the context.
+  while (curClassDecl != dcClassDecl) {
+    // Map to the superclass type.
+    QualType superType = objectType->getSuperClassType();
+    if (superType.isNull()) {
+      objectType = nullptr;
+      break;
+    }
+
+    objectType = superType->castAs<ObjCObjectType>();
+    curClassDecl = objectType->getInterface();
+  }
+
+  // If we don't have a receiver type, or the receiver type does not
+  // have type arguments, substitute in the defaults.
+  if (!objectType || objectType->isUnspecialized()) {
+    return llvm::ArrayRef<QualType>();
+  }
+
+  // The receiver type has the type arguments we want.
+  return objectType->getTypeArgs();
+}
+
+void ObjCObjectType::computeSuperClassTypeSlow() const {
+  // Retrieve the class declaration for this type. If there isn't one
+  // (e.g., this is some variant of "id" or "Class"), then there is no
+  // superclass type.
+  ObjCInterfaceDecl *classDecl = getInterface();
+  if (!classDecl) {
+    CachedSuperClassType.setInt(true);
+    return;
+  }
+
+  // Extract the superclass type.
+  const ObjCObjectType *superClassObjTy = classDecl->getSuperClassType();
+  if (!superClassObjTy) {
+    CachedSuperClassType.setInt(true);
+    return;
+  }
+
+  ObjCInterfaceDecl *superClassDecl = superClassObjTy->getInterface();
+  if (!superClassDecl) {
+    CachedSuperClassType.setInt(true);
+    return;
+  }
+
+  // If the superclass doesn't have type parameters, then there is no
+  // substitution to perform.
+  QualType superClassType(superClassObjTy, 0);
+  ObjCTypeParamList *superClassTypeParams = superClassDecl->getTypeParamList();
+  if (!superClassTypeParams) {
+    CachedSuperClassType.setPointerAndInt(
+      superClassType->castAs<ObjCObjectType>(), true);
+    return;
+  }
+
+  // If the superclass reference is unspecialized, return it.
+  if (superClassObjTy->isUnspecialized()) {
+    CachedSuperClassType.setPointerAndInt(superClassObjTy, true);
+    return;
+  }
+
+  // If the subclass is not parameterized, there aren't any type
+  // parameters in the superclass reference to substitute.
+  ObjCTypeParamList *typeParams = classDecl->getTypeParamList();
+  if (!typeParams) {
+    CachedSuperClassType.setPointerAndInt(
+      superClassType->castAs<ObjCObjectType>(), true);
+    return;
+  }
+
+  // If the subclass type isn't specialized, return the unspecialized
+  // superclass.
+  if (isUnspecialized()) {
+    QualType unspecializedSuper
+      = classDecl->getASTContext().getObjCInterfaceType(
+          superClassObjTy->getInterface());
+    CachedSuperClassType.setPointerAndInt(
+      unspecializedSuper->castAs<ObjCObjectType>(),
+      true);
+    return;
+  }
+
+  // Substitute the provided type arguments into the superclass type.
+  ArrayRef<QualType> typeArgs = getTypeArgs();
+  assert(typeArgs.size() == typeParams->size());
+  CachedSuperClassType.setPointerAndInt(
+    superClassType.substObjCTypeArgs(classDecl->getASTContext(), typeArgs,
+                                     ObjCSubstitutionContext::Superclass)
+      ->castAs<ObjCObjectType>(),
+    true);
+}
+
+QualType ObjCObjectPointerType::getSuperClassType() const {
+  QualType superObjectType = getObjectType()->getSuperClassType();
+  if (superObjectType.isNull())
+    return superObjectType;
+
+  ASTContext &ctx = getInterfaceDecl()->getASTContext();
+  return ctx.getObjCObjectPointerType(superObjectType);
+}
 
 const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const {
   // There is no sugar for ObjCObjectType's, just return the canonical
@@ -551,6 +1303,13 @@ const ObjCObjectPointerType *Type::getAs
   return nullptr;
 }
 
+const ObjCObjectType *Type::getAsObjCInterfaceType() const {
+  if (const ObjCObjectType *OT = getAs<ObjCObjectType>()) {
+    if (OT->getInterface())
+      return OT;
+  }
+  return nullptr;
+}
 const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
   if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
     if (OPT->getInterfaceType())

Modified: cfe/trunk/lib/AST/TypeLoc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeLoc.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypeLoc.cpp (original)
+++ cfe/trunk/lib/AST/TypeLoc.cpp Mon Jul  6 22:57:53 2015
@@ -312,6 +312,17 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLo
   return TL;
 }
 
+SourceLocation TypeLoc::findNullabilityLoc() const {
+  if (auto attributedLoc = getAs<AttributedTypeLoc>()) {
+    if (attributedLoc.getAttrKind() == AttributedType::attr_nullable ||
+        attributedLoc.getAttrKind() == AttributedType::attr_nonnull ||
+        attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified)
+      return attributedLoc.getAttrNameLoc();
+  }
+
+  return SourceLocation();
+}
+
 void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, 
                                         SourceLocation Loc) {
   setHasBaseTypeAsWritten(true);

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Mon Jul  6 22:57:53 2015
@@ -31,10 +31,9 @@ using namespace CodeGen;
 typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult;
 static TryEmitResult
 tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
-static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
-                                      QualType ET,
-                                      const ObjCMethodDecl *Method,
-                                      RValue Result);
+static RValue AdjustObjCObjectType(CodeGenFunction &CGF,
+                                   QualType ET,
+                                   RValue Result);
 
 /// Given the address of a variable of pointer type, find the correct
 /// null to store into it.
@@ -248,23 +247,22 @@ llvm::Value *CodeGenFunction::EmitObjCPr
   return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol());
 }
 
-/// \brief Adjust the type of the result of an Objective-C message send 
-/// expression when the method has a related result type.
-static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
-                                      QualType ExpT,
-                                      const ObjCMethodDecl *Method,
-                                      RValue Result) {
-  if (!Method)
+/// \brief Adjust the type of an Objective-C object that doesn't match up due
+/// to type erasure at various points, e.g., related result types or the use
+/// of parameterized classes.
+static RValue AdjustObjCObjectType(CodeGenFunction &CGF, QualType ExpT,
+                                   RValue Result) {
+  if (!ExpT->isObjCRetainableType())
     return Result;
 
-  if (!Method->hasRelatedResultType() ||
-      CGF.getContext().hasSameType(ExpT, Method->getReturnType()) ||
-      !Result.isScalar())
+  // If the converted types are the same, we're done.
+  llvm::Type *ExpLLVMTy = CGF.ConvertType(ExpT);
+  if (ExpLLVMTy == Result.getScalarVal()->getType())
     return Result;
-  
-  // We have applied a related result type. Cast the rvalue appropriately.
+
+  // We have applied a substitution. Cast the rvalue appropriately.
   return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(),
-                                               CGF.ConvertType(ExpT)));
+                                               ExpLLVMTy));
 }
 
 /// Decide whether to extend the lifetime of the receiver of a
@@ -449,7 +447,7 @@ RValue CodeGenFunction::EmitObjCMessageE
     Builder.CreateStore(newSelf, selfAddr);
   }
 
-  return AdjustRelatedResultType(*this, E->getType(), method, result);
+  return AdjustObjCObjectType(*this, E->getType(), result);
 }
 
 namespace {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Jul  6 22:57:53 2015
@@ -2943,6 +2943,26 @@ private:
                                   SourceLocation Loc);
 
 public:
+#ifndef NDEBUG
+  // Determine whether the given argument is an Objective-C method
+  // that may have type parameters in its signature.
+  static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) {
+    const DeclContext *dc = method->getDeclContext();
+    if (const ObjCInterfaceDecl *classDecl= dyn_cast<ObjCInterfaceDecl>(dc)) {
+      return classDecl->getTypeParamListAsWritten();
+    }
+
+    if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) {
+      return catDecl->getTypeParamList();
+    }
+
+    return false;
+  }
+
+  template<typename T>
+  static bool isObjCMethodWithTypeParams(const T *) { return false; }
+#endif
+
   /// EmitCallArgs - Emit call arguments for a function.
   template <typename T>
   void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
@@ -2956,13 +2976,19 @@ public:
     assert((ParamsToSkip == 0 || CallArgTypeInfo) &&
            "Can't skip parameters if type info is not provided");
     if (CallArgTypeInfo) {
+#ifndef NDEBUG
+      bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo);
+#endif
+
       // First, use the argument types that the type info knows about
       for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip,
                 E = CallArgTypeInfo->param_type_end();
            I != E; ++I, ++Arg) {
         assert(Arg != ArgEnd && "Running over edge of argument list!");
         assert(
+            isGenericMethod ||
             ((*I)->isVariablyModifiedType() ||
+             (*I).getNonReferenceType()->isObjCRetainableType() ||
              getContext()
                      .getCanonicalType((*I).getNonReferenceType())
                      .getTypePtr() ==

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul  6 22:57:53 2015
@@ -2890,21 +2890,7 @@ void Parser::ParseDeclarationSpecifiers(
       // following an Objective-C object pointer type. Handle either
       // one of them.
       if (Tok.is(tok::less) && getLangOpts().ObjC1) {
-        ParseObjCTypeArgsOrProtocolQualifiers(
-          DS, /*warnOnIncompleteProtocols=*/false);
-
-        // An Objective-C object pointer followed by type arguments
-        // can then be followed again by a set of protocol references, e.g.,
-        // \c NSArray<NSView><NSTextDelegate>
-        if (Tok.is(tok::less)) {
-          if (DS.getProtocolQualifiers()) {
-            Diag(Tok, diag::err_objc_type_args_after_protocols)
-              << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
-            SkipUntil(tok::greater, tok::greatergreater);
-          } else {
-            ParseObjCProtocolQualifiers(DS);
-          }
-        }
+        ParseObjCTypeArgsAndProtocolQualifiers(DS);
       }
 
       continue;
@@ -3016,21 +3002,7 @@ void Parser::ParseDeclarationSpecifiers(
       // following an Objective-C object pointer type. Handle either
       // one of them.
       if (Tok.is(tok::less) && getLangOpts().ObjC1) {
-        ParseObjCTypeArgsOrProtocolQualifiers(
-          DS, /*warnOnIncompleteProtocols=*/false);
-
-        // An Objective-C object pointer followed by type arguments
-        // can then be followed again by a set of protocol references, e.g.,
-        // \c NSArray<NSView><NSTextDelegate>
-        if (Tok.is(tok::less)) {
-          if (DS.getProtocolQualifiers()) {
-            Diag(Tok, diag::err_objc_type_args_after_protocols)
-              << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
-            SkipUntil(tok::greater, tok::greatergreater);
-          } else {
-            ParseObjCProtocolQualifiers(DS);
-          }
-        }
+        ParseObjCTypeArgsAndProtocolQualifiers(DS);
       }
 
       // Need to support trailing type qualifiers (e.g. "id<p> const").

Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Mon Jul  6 22:57:53 2015
@@ -258,20 +258,33 @@ ExprResult Parser::ParseInitializerWithP
                                              NextToken().is(tok::period),
                                              ReceiverType)) {
       case Sema::ObjCSuperMessage:
+        CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+        return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+                                                           ConsumeToken(),
+                                                           ParsedType(),
+                                                           nullptr);
+
       case Sema::ObjCClassMessage:
         CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
-        if (Kind == Sema::ObjCSuperMessage)
-          return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
-                                                             ConsumeToken(),
-                                                             ParsedType(),
-                                                             nullptr);
         ConsumeToken(); // the identifier
         if (!ReceiverType) {
           SkipUntil(tok::r_square, StopAtSemi);
           return ExprError();
         }
 
-        return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, 
+        // Parse type arguments and protocol qualifiers.
+        if (Tok.is(tok::less)) {
+          TypeResult NewReceiverType
+            = ParseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType);
+          if (!NewReceiverType.isUsable()) {
+            SkipUntil(tok::r_square, StopAtSemi);
+            return ExprError();
+          }
+
+          ReceiverType = NewReceiverType.get();
+        }
+
+        return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
                                                            SourceLocation(), 
                                                            ReceiverType, 
                                                            nullptr);

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Mon Jul  6 22:57:53 2015
@@ -438,8 +438,10 @@ ObjCTypeParamList *Parser::parseObjCType
   // type parameters.
   SmallVector<Decl *, 4> typeParams;
   auto makeProtocolIdentsIntoTypeParameters = [&]() {
+    unsigned index = 0;
     for (const auto &pair : protocolIdents) {
       DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
+                                                        index++,
                                                         pair.first,
                                                         pair.second,
                                                         SourceLocation(),
@@ -502,6 +504,7 @@ ObjCTypeParamList *Parser::parseObjCType
 
     // Create the type parameter.
     DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
+                                                      typeParams.size(),
                                                       paramName,
                                                       paramLoc,
                                                       colonLoc,
@@ -1675,6 +1678,45 @@ void Parser::ParseObjCTypeArgsOrProtocol
   DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
 }
 
+void Parser::ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS) {
+  assert(Tok.is(tok::less));
+
+  ParseObjCTypeArgsOrProtocolQualifiers(DS,
+                                        /*warnOnIncompleteProtocols=*/false);
+
+  // An Objective-C object pointer followed by type arguments
+  // can then be followed again by a set of protocol references, e.g.,
+  // \c NSArray<NSView><NSTextDelegate>
+  if (Tok.is(tok::less)) {
+    if (DS.getProtocolQualifiers()) {
+      Diag(Tok, diag::err_objc_type_args_after_protocols)
+        << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
+      SkipUntil(tok::greater, tok::greatergreater);
+    } else {
+      ParseObjCProtocolQualifiers(DS);
+    }
+  }
+}
+
+TypeResult Parser::ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
+                                                          ParsedType type) {
+  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());
+
+  // Parse type arguments and protocol qualifiers.
+  ParseObjCTypeArgsAndProtocolQualifiers(DS);
+
+  // Form a declarator to turn this into a type.
+  Declarator D(DS, Declarator::TypeNameContext);
+  return Actions.ActOnTypeName(getCurScope(), D);
+}
+
 void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
                                  BalancedDelimiterTracker &T,
                                  SmallVectorImpl<Decl *> &AllIvarDecls,
@@ -2829,6 +2871,18 @@ ExprResult Parser::ParseObjCMessageExpre
 
       ConsumeToken(); // the type name
 
+      // Parse type arguments and protocol qualifiers.
+      if (Tok.is(tok::less)) {
+        TypeResult NewReceiverType
+          = ParseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType);
+        if (!NewReceiverType.isUsable()) {
+          SkipUntil(tok::r_square, StopAtSemi);
+          return ExprError();
+        }
+
+        ReceiverType = NewReceiverType.get();
+      }
+
       return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 
                                             ReceiverType, nullptr);
 

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Jul  6 22:57:53 2015
@@ -600,7 +600,8 @@ ActOnSuperClassOfClassInterface(Scope *S
   }
 }
 
-DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
+DeclResult Sema::actOnObjCTypeParam(Scope *S, unsigned index,
+                                    IdentifierInfo *paramName,
                                     SourceLocation paramLoc,
                                     SourceLocation colonLoc,
                                     ParsedType parsedTypeBound) {
@@ -643,6 +644,23 @@ DeclResult Sema::actOnObjCTypeParam(Scop
       // Forget the bound; we'll default to id later.
       typeBoundInfo = nullptr;
     }
+
+    // Type bounds cannot have explicit nullability.
+    if (typeBoundInfo) {
+      // Type arguments cannot explicitly specify nullability.
+      if (auto nullability = AttributedType::stripOuterNullability(typeBound)) {
+        // Look at the type location information to find the nullability
+        // specifier so we can zap it.
+        SourceLocation nullabilityLoc
+          = typeBoundInfo->getTypeLoc().findNullabilityLoc();
+        SourceLocation diagLoc
+          = nullabilityLoc.isValid()? nullabilityLoc
+                                    : typeBoundInfo->getTypeLoc().getLocStart();
+        Diag(diagLoc, diag::err_type_param_bound_explicit_nullability)
+          << paramName << typeBoundInfo->getType()
+          << FixItHint::CreateRemoval(nullabilityLoc);
+      }
+    }
   }
 
   // If there was no explicit type bound (or we removed it due to an error),
@@ -653,8 +671,8 @@ DeclResult Sema::actOnObjCTypeParam(Scop
   }
 
   // Create the type parameter.
-  return ObjCTypeParamDecl::Create(Context, CurContext, paramLoc, paramName,
-                                   colonLoc, typeBoundInfo);
+  return ObjCTypeParamDecl::Create(Context, CurContext, index, paramLoc, 
+                                   paramName, colonLoc, typeBoundInfo);
 }
 
 ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S,
@@ -868,6 +886,7 @@ ActOnStartClassInterface(Scope *S, Sourc
             ObjCTypeParamDecl::Create(
               Context,
               CurContext,
+              typeParam->getIndex(),
               SourceLocation(),
               typeParam->getIdentifier(),
               SourceLocation(),

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jul  6 22:57:53 2015
@@ -2466,8 +2466,8 @@ Sema::LookupInObjCMethod(LookupResult &L
         Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
 
       ObjCIvarRefExpr *Result = new (Context)
-          ObjCIvarRefExpr(IV, IV->getType(), Loc, IV->getLocation(),
-                          SelfExpr.get(), true, true);
+          ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
+                          IV->getLocation(), SelfExpr.get(), true, true);
 
       if (getLangOpts().ObjCAutoRefCount) {
         if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
@@ -5185,17 +5185,17 @@ Sema::ActOnInitList(SourceLocation LBrac
 }
 
 /// Do an explicit extend of the given block pointer if we're in ARC.
-static void maybeExtendBlockObject(Sema &S, ExprResult &E) {
+void Sema::maybeExtendBlockObject(ExprResult &E) {
   assert(E.get()->getType()->isBlockPointerType());
   assert(E.get()->isRValue());
 
   // Only do this in an r-value context.
-  if (!S.getLangOpts().ObjCAutoRefCount) return;
+  if (!getLangOpts().ObjCAutoRefCount) return;
 
-  E = ImplicitCastExpr::Create(S.Context, E.get()->getType(),
+  E = ImplicitCastExpr::Create(Context, E.get()->getType(),
                                CK_ARCExtendBlockObject, E.get(),
                                /*base path*/ nullptr, VK_RValue);
-  S.ExprNeedsCleanups = true;
+  ExprNeedsCleanups = true;
 }
 
 /// Prepare a conversion of the given expression to an ObjC object
@@ -5205,7 +5205,7 @@ CastKind Sema::PrepareCastToObjCObjectPo
   if (type->isObjCObjectPointerType()) {
     return CK_BitCast;
   } else if (type->isBlockPointerType()) {
-    maybeExtendBlockObject(*this, E);
+    maybeExtendBlockObject(E);
     return CK_BlockPointerToObjCPointerCast;
   } else {
     assert(type->isPointerType());
@@ -5247,7 +5247,7 @@ CastKind Sema::PrepareScalarCast(ExprRes
         return CK_BitCast;
       if (SrcKind == Type::STK_CPointer)
         return CK_CPointerToObjCPointerCast;
-      maybeExtendBlockObject(*this, Src);
+      maybeExtendBlockObject(Src);
       return CK_BlockPointerToObjCPointerCast;
     case Type::STK_Bool:
       return CK_PointerToBoolean;
@@ -6980,7 +6980,7 @@ Sema::CheckAssignmentConstraints(QualTyp
     // Only under strict condition T^ is compatible with an Objective-C pointer.
     if (RHSType->isBlockPointerType() && 
         LHSType->isBlockCompatibleObjCPointerType(Context)) {
-      maybeExtendBlockObject(*this, RHS);
+      maybeExtendBlockObject(RHS);
       Kind = CK_BlockPointerToObjCPointerCast;
       return Compatible;
     }
@@ -8189,9 +8189,6 @@ static bool hasIsEqualMethod(Sema &S, co
 
   // Get the LHS object's interface type.
   QualType InterfaceType = Type->getPointeeType();
-  if (const ObjCObjectType *iQFaceTy =
-      InterfaceType->getAsObjCQualifiedInterfaceType())
-    InterfaceType = iQFaceTy->getBaseType();
 
   // If the RHS isn't an Objective-C object, bail out.
   if (!RHS->getType()->isObjCObjectPointerType())

Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprMember.cpp Mon Jul  6 22:57:53 2015
@@ -1378,7 +1378,8 @@ static ExprResult LookupMemberExpr(Sema
     }
 
     ObjCIvarRefExpr *Result = new (S.Context) ObjCIvarRefExpr(
-        IV, IV->getType(), MemberLoc, OpLoc, BaseExpr.get(), IsArrow);
+        IV, IV->getUsageType(BaseType), MemberLoc, OpLoc, BaseExpr.get(),
+        IsArrow);
 
     if (S.getLangOpts().ObjCAutoRefCount) {
       if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Jul  6 22:57:53 2015
@@ -1281,7 +1281,7 @@ static QualType getBaseMessageSendResult
                                              bool isSuperMessage) {
   assert(Method && "Must have a method");
   if (!Method->hasRelatedResultType())
-    return Method->getSendResultType();
+    return Method->getSendResultType(ReceiverType);
 
   ASTContext &Context = S.Context;
 
@@ -1289,7 +1289,8 @@ static QualType getBaseMessageSendResult
   // result type to the returned result.
   auto transferNullability = [&](QualType type) -> QualType {
     // If the method's result type has nullability, extract it.
-    if (auto nullability = Method->getSendResultType()->getNullability(Context)){
+    if (auto nullability = Method->getSendResultType(ReceiverType)
+                             ->getNullability(Context)){
       // Strip off any outer nullability sugar from the provided type.
       (void)AttributedType::stripOuterNullability(type);
 
@@ -1308,7 +1309,8 @@ static QualType getBaseMessageSendResult
   //     was a class message send, T is the declared return type of the method
   //     found
   if (Method->isInstanceMethod() && isClassMessage)
-    return stripObjCInstanceType(Context, Method->getSendResultType());
+    return stripObjCInstanceType(Context, 
+                                 Method->getSendResultType(ReceiverType));
 
   //   - if the receiver is super, T is a pointer to the class of the
   //     enclosing method definition
@@ -1322,14 +1324,14 @@ static QualType getBaseMessageSendResult
   }
 
   //   - if the receiver is the name of a class U, T is a pointer to U
-  if (ReceiverType->getAs<ObjCInterfaceType>() ||
-      ReceiverType->isObjCQualifiedInterfaceType())
+  if (ReceiverType->getAsObjCInterfaceType())
     return transferNullability(Context.getObjCObjectPointerType(ReceiverType));
   //   - if the receiver is of type Class or qualified Class type,
   //     T is the declared return type of the method.
   if (ReceiverType->isObjCClassType() ||
       ReceiverType->isObjCQualifiedClassType())
-    return stripObjCInstanceType(Context, Method->getSendResultType());
+    return stripObjCInstanceType(Context, 
+                                 Method->getSendResultType(ReceiverType));
 
   //   - if the receiver is id, qualified id, Class, or qualified Class, T
   //     is the receiver type, otherwise
@@ -1592,6 +1594,10 @@ bool Sema::CheckMessageArgumentTypes(Qua
     return false;
   }
 
+  // Compute the set of type arguments to be substituted into each parameter
+  // type.
+  Optional<ArrayRef<QualType>> typeArgs
+    = ReceiverType->getObjCSubstitutions(Method->getDeclContext());
   bool IsError = false;
   for (unsigned i = 0; i < NumNamedArgs; i++) {
     // We can't do any type-checking on a type-dependent argument.
@@ -1625,18 +1631,37 @@ bool Sema::CheckMessageArgumentTypes(Qua
       continue;
     }
 
+    QualType origParamType = param->getType();
+    QualType paramType = param->getType();
+    if (typeArgs)
+      paramType = paramType.substObjCTypeArgs(
+                    Context,
+                    *typeArgs,
+                    ObjCSubstitutionContext::Parameter);
+
     if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
-                            param->getType(),
+                            paramType,
                             diag::err_call_incomplete_argument, argExpr))
       return true;
 
-    InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
-                                                                      param);
+    InitializedEntity Entity
+      = InitializedEntity::InitializeParameter(Context, param, paramType);
     ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr);
     if (ArgE.isInvalid())
       IsError = true;
-    else
+    else {
       Args[i] = ArgE.getAs<Expr>();
+
+      // If we are type-erasing a block to a block-compatible
+      // Objective-C pointer type, we may need to extend the lifetime
+      // of the block object.
+      if (typeArgs && Args[i]->isRValue() && paramType->isBlockPointerType() &&
+          origParamType->isBlockCompatibleObjCPointerType(Context)) {
+        ExprResult arg = Args[i];
+        maybeExtendBlockObject(arg);
+        Args[i] = arg.get();
+      }
+    }
   }
 
   // Promote additional arguments to variadic methods.
@@ -1904,27 +1929,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo
   ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
                                                   receiverNameLoc);
 
-  bool IsSuper = false;
+  QualType SuperType;
   if (!IFace) {
     // If the "receiver" is 'super' in a method, handle it as an expression-like
     // property reference.
     if (receiverNamePtr->isStr("super")) {
-      IsSuper = true;
-
       if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) {
-        if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) {
+        if (auto classDecl = CurMethod->getClassInterface()) {
+          SuperType = QualType(classDecl->getSuperClassType(), 0);
           if (CurMethod->isInstanceMethod()) {
-            ObjCInterfaceDecl *Super = Class->getSuperClass();
-            if (!Super) {
+            if (SuperType.isNull()) {
               // The current class does not have a superclass.
               Diag(receiverNameLoc, diag::error_root_class_cannot_use_super)
-              << Class->getIdentifier();
+                << CurMethod->getClassInterface()->getIdentifier();
               return ExprError();
             }
-            QualType T = Context.getObjCInterfaceType(Super);
-            T = Context.getObjCObjectPointerType(T);
+            QualType T = Context.getObjCObjectPointerType(SuperType);
 
-            return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
+            return HandleExprPropertyRefExpr(T->castAs<ObjCObjectPointerType>(),
                                              /*BaseExpr*/nullptr,
                                              SourceLocation()/*OpLoc*/,
                                              &propertyName,
@@ -1934,7 +1956,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo
 
           // Otherwise, if this is a class method, try dispatching to our
           // superclass.
-          IFace = Class->getSuperClass();
+          IFace = CurMethod->getClassInterface()->getSuperClass();
         }
       }
     }
@@ -1964,7 +1986,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo
   // Look for the matching setter, in case it is needed.
   Selector SetterSel =
     SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
-                                           PP.getSelectorTable(),
+                                            PP.getSelectorTable(),
                                            &propertyName);
 
   ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
@@ -1981,11 +2003,11 @@ ActOnClassPropertyRefExpr(IdentifierInfo
     return ExprError();
 
   if (Getter || Setter) {
-    if (IsSuper)
+    if (!SuperType.isNull())
       return new (Context)
           ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
                               OK_ObjCProperty, propertyNameLoc, receiverNameLoc,
-                              Context.getObjCInterfaceType(IFace));
+                              SuperType);
 
     return new (Context) ObjCPropertyRefExpr(
         Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty,
@@ -2132,8 +2154,8 @@ ExprResult Sema::ActOnSuperMessage(Scope
     return ExprError();
   }
 
-  ObjCInterfaceDecl *Super = Class->getSuperClass();
-  if (!Super) {
+  QualType SuperTy(Class->getSuperClassType(), 0);
+  if (SuperTy.isNull()) {
     // The current class does not have a superclass.
     Diag(SuperLoc, diag::error_root_class_cannot_use_super)
       << Class->getIdentifier();
@@ -2148,7 +2170,6 @@ ExprResult Sema::ActOnSuperMessage(Scope
   if (Method->isInstanceMethod()) {
     // Since we are in an instance method, this is an instance
     // message to the superclass instance.
-    QualType SuperTy = Context.getObjCInterfaceType(Super);
     SuperTy = Context.getObjCObjectPointerType(SuperTy);
     return BuildInstanceMessage(nullptr, SuperTy, SuperLoc,
                                 Sel, /*Method=*/nullptr,
@@ -2158,7 +2179,7 @@ ExprResult Sema::ActOnSuperMessage(Scope
   // Since we are in a class method, this is a class message to
   // the superclass.
   return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr,
-                           Context.getObjCInterfaceType(Super),
+                           SuperTy,
                            SuperLoc, Sel, /*Method=*/nullptr,
                            LBracLoc, SelectorLocs, RBracLoc, Args);
 }

Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Mon Jul  6 22:57:53 2015
@@ -1157,7 +1157,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope
                                  CK_LValueToRValue, SelfExpr, nullptr,
                                  VK_RValue);
       Expr *IvarRefExpr =
-        new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
+        new (Context) ObjCIvarRefExpr(Ivar,
+                                      Ivar->getUsageType(SelfDecl->getType()),
+                                      PropertyDiagLoc,
                                       Ivar->getLocation(),
                                       LoadSelfExpr, true, true);
       ExprResult Res = PerformCopyInitialization(
@@ -1207,7 +1209,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope
                                  CK_LValueToRValue, SelfExpr, nullptr,
                                  VK_RValue);
       Expr *lhs =
-        new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
+        new (Context) ObjCIvarRefExpr(Ivar,
+                                      Ivar->getUsageType(SelfDecl->getType()),
+                                      PropertyDiagLoc,
                                       Ivar->getLocation(),
                                       LoadSelfExpr, true, true);
       ObjCMethodDecl::param_iterator P = setterMethod->param_begin();

Modified: cfe/trunk/lib/Sema/SemaPseudoObject.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaPseudoObject.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaPseudoObject.cpp (original)
+++ cfe/trunk/lib/Sema/SemaPseudoObject.cpp Mon Jul  6 22:57:53 2015
@@ -689,15 +689,7 @@ ExprResult ObjCPropertyOpBuilder::buildG
   if (SyntacticRefExpr)
     SyntacticRefExpr->setIsMessagingGetter();
 
-  QualType receiverType;
-  if (RefExpr->isClassReceiver()) {
-    receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());
-  } else if (RefExpr->isSuperReceiver()) {
-    receiverType = RefExpr->getSuperReceiverType();
-  } else {
-    assert(InstanceReceiver);
-    receiverType = InstanceReceiver->getType();
-  }
+  QualType receiverType = RefExpr->getReceiverType(S.Context);
   if (!Getter->isImplicit())
     S.DiagnoseUseOfDecl(Getter, GenericLoc, nullptr, true);
   // Build a message-send.
@@ -730,21 +722,17 @@ ExprResult ObjCPropertyOpBuilder::buildS
   if (SyntacticRefExpr)
     SyntacticRefExpr->setIsMessagingSetter();
 
-  QualType receiverType;
-  if (RefExpr->isClassReceiver()) {
-    receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());
-  } else if (RefExpr->isSuperReceiver()) {
-    receiverType = RefExpr->getSuperReceiverType();
-  } else {
-    assert(InstanceReceiver);
-    receiverType = InstanceReceiver->getType();
-  }
+  QualType receiverType = RefExpr->getReceiverType(S.Context);
 
   // Use assignment constraints when possible; they give us better
   // diagnostics.  "When possible" basically means anything except a
   // C++ class type.
   if (!S.getLangOpts().CPlusPlus || !op->getType()->isRecordType()) {
-    QualType paramType = (*Setter->param_begin())->getType();
+    QualType paramType = (*Setter->param_begin())->getType()
+                           .substObjCMemberType(
+                             receiverType,
+                             Setter->getDeclContext(),
+                             ObjCSubstitutionContext::Parameter);
     if (!S.getLangOpts().CPlusPlus || !paramType->isRecordType()) {
       ExprResult opResult = op;
       Sema::AssignConvertType assignResult
@@ -819,7 +807,9 @@ ExprResult ObjCPropertyOpBuilder::buildR
   // As a special case, if the method returns 'id', try to get
   // a better type from the property.
   if (RefExpr->isExplicitProperty() && result.get()->isRValue()) {
-    QualType propType = RefExpr->getExplicitProperty()->getType();
+    QualType receiverType = RefExpr->getReceiverType(S.Context);
+    QualType propType = RefExpr->getExplicitProperty()
+                          ->getUsageType(receiverType);
     if (result.get()->getType()->isObjCIdType()) {
       if (const ObjCObjectPointerType *ptr
             = propType->getAs<ObjCObjectPointerType>()) {
@@ -1119,9 +1109,6 @@ bool ObjCSubscriptOpBuilder::findAtIndex
   if (const ObjCObjectPointerType *PTy =
       BaseT->getAs<ObjCObjectPointerType>()) {
     ResultType = PTy->getPointeeType();
-    if (const ObjCObjectType *iQFaceTy = 
-        ResultType->getAsObjCQualifiedInterfaceType())
-      ResultType = iQFaceTy->getBaseType();
   }
   Sema::ObjCSubscriptKind Res = 
     S.CheckSubscriptingKind(RefExpr->getKeyExpr());
@@ -1228,9 +1215,6 @@ bool ObjCSubscriptOpBuilder::findAtIndex
   if (const ObjCObjectPointerType *PTy =
       BaseT->getAs<ObjCObjectPointerType>()) {
     ResultType = PTy->getPointeeType();
-    if (const ObjCObjectType *iQFaceTy = 
-        ResultType->getAsObjCQualifiedInterfaceType())
-      ResultType = iQFaceTy->getBaseType();
   }
   
   Sema::ObjCSubscriptKind Res = 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jul  6 22:57:53 2015
@@ -786,6 +786,19 @@ static QualType applyObjCTypeArgs(Sema &
   for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) {
     TypeSourceInfo *typeArgInfo = nullptr;
     QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo);
+
+    // Type arguments cannot explicitly specify nullability.
+    if (auto nullability = AttributedType::stripOuterNullability(typeArg)) {
+      SourceLocation nullabilityLoc
+        = typeArgInfo->getTypeLoc().findNullabilityLoc();
+      SourceLocation diagLoc = nullabilityLoc.isValid()? nullabilityLoc
+        : typeArgInfo->getTypeLoc().getLocStart();
+      S.Diag(diagLoc,
+             diag::err_type_arg_explicit_nullability)
+        << typeArg
+        << FixItHint::CreateRemoval(nullabilityLoc);
+    }
+
     finalTypeArgs.push_back(typeArg);
 
     // Objective-C object pointer types must be substitutable for the bounds.
@@ -3257,7 +3270,6 @@ static TypeSourceInfo *GetFullTypeForDec
     case CAMN_Yes:
       checkNullabilityConsistency(state, pointerKind, pointerLoc);
     }
-
     return nullptr;
   };
 

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Jul  6 22:57:53 2015
@@ -904,6 +904,7 @@ void ASTDeclReader::VisitObjCMethodDecl(
 
 void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
   VisitTypedefNameDecl(D);
+  D->Index = Record[Idx++];
   D->ColonLoc = ReadSourceLocation(Record, Idx);
 }
 

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Jul  6 22:57:53 2015
@@ -421,8 +421,8 @@ void ASTTypeWriter::VisitObjCInterfaceTy
 
 void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
   Writer.AddTypeRef(T->getBaseType(), Record);
-  Record.push_back(T->getTypeArgs().size());
-  for (auto TypeArg : T->getTypeArgs())
+  Record.push_back(T->getTypeArgsAsWritten().size());
+  for (auto TypeArg : T->getTypeArgsAsWritten())
     Writer.AddTypeRef(TypeArg, Record);
   Record.push_back(T->getNumProtocols());
   for (const auto *I : T->quals())

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Mon Jul  6 22:57:53 2015
@@ -581,6 +581,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(
 
 void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
   VisitTypedefNameDecl(D);
+  Record.push_back(D->Index);
   Writer.AddSourceLocation(D->ColonLoc, Record);
 
   Code = serialization::DECL_OBJC_TYPE_PARAM;

Added: cfe/trunk/test/CodeGenObjC/parameterized_classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/parameterized_classes.m?rev=241543&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/parameterized_classes.m (added)
+++ cfe/trunk/test/CodeGenObjC/parameterized_classes.m Mon Jul  6 22:57:53 2015
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-arc -emit-llvm -o - %s | FileCheck %s
+
+// Parameterized classes have no effect on code generation; this test
+// mainly verifies that CodeGen doesn't assert when substituted types
+// in uses of methods don't line up exactly with the parameterized
+// types in the method declarations due to type erasure. "Not crash"
+// is the only interesting criteria here.
+
+ at protocol NSObject
+ at end
+
+ at protocol NSCopying
+ at end
+
+__attribute__((objc_root_class))
+ at interface NSObject <NSObject>
+ at end
+
+ at interface NSString : NSObject <NSCopying>
+ at end
+
+ at interface NSMutableArray<T> : NSObject <NSCopying>
+ at property (copy,nonatomic) T firstObject;
+- (void)addObject:(T)object;
+- (void)sortWithFunction:(int (*)(T, T))function;
+- (void)getObjects:(T __strong *)objects length:(unsigned*)length;
+ at end
+
+NSString *getFirstObjectProp(NSMutableArray<NSString *> *array) {
+  return array.firstObject;
+}
+
+NSString *getFirstObjectMethod(NSMutableArray<NSString *> *array) {
+  return [array firstObject];
+}
+
+void addObject(NSMutableArray<NSString *> *array, NSString *obj) {
+  [array addObject: obj];
+}
+
+int compareStrings(NSString *x, NSString *y) { return 0; }
+int compareBlocks(NSString * (^x)(NSString *),
+                  NSString * (^y)(NSString *)) { return 0; }
+
+void sortTest(NSMutableArray<NSString *> *array,
+              NSMutableArray<NSString * (^)(NSString *)> *array2) {
+  [array sortWithFunction: &compareStrings];
+  [array2 sortWithFunction: &compareBlocks];
+}
+
+void getObjectsTest(NSMutableArray<NSString *> *array) {
+  NSString * __strong *objects;
+  unsigned length;
+  [array getObjects: objects length: &length];
+}
+
+void printMe(NSString *name) { }
+
+// CHECK-LABEL: define void @blockTest
+void blockTest(NSMutableArray<void (^)(void)> *array, NSString *name) {
+  // CHECK: call i8* @objc_retainBlock
+  [array addObject: ^ { printMe(name); }];
+}

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

Modified: cfe/trunk/test/SemaObjC/parameterized_classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes.m?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/parameterized_classes.m (original)
+++ cfe/trunk/test/SemaObjC/parameterized_classes.m Mon Jul  6 22:57:53 2015
@@ -173,29 +173,17 @@ __attribute__((objc_root_class))
   T object;
 }
 
-- (U)method:(V)param; // expected-note{{passing argument to parameter 'param' here}}
+- (U)method:(V)param;
 @end
 
 @interface PC20<T, U, V> (Cat1)
-- (U)catMethod:(V)param; // expected-note{{passing argument to parameter 'param' here}}
+- (U)catMethod:(V)param;
 @end
 
 @interface PC20<X, Y, Z>()
-- (X)extMethod:(Y)param; // expected-note{{passing argument to parameter 'param' here}}
+- (X)extMethod:(Y)param;
 @end
 
-void test_PC20_unspecialized(PC20 *pc20) {
-  // FIXME: replace type parameters with underlying types?
-  int *ip = [pc20 method: 0]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'U' (aka 'NSObject *')}}
-  [pc20 method: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
-
-  ip = [pc20 catMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'U' (aka 'NSObject *')}}
-  [pc20 catMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
-
-  ip = [pc20 extMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'X' (aka 'id')}}
-  [pc20 extMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'Y' (aka 'NSObject *')}}
-}
-
 // --------------------------------------------------------------------------
 // Parsing type arguments.
 // --------------------------------------------------------------------------

Added: cfe/trunk/test/SemaObjC/parameterized_classes_subst.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes_subst.m?rev=241543&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/parameterized_classes_subst.m (added)
+++ cfe/trunk/test/SemaObjC/parameterized_classes_subst.m Mon Jul  6 22:57:53 2015
@@ -0,0 +1,372 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -Wnullable-to-nonnull-conversion %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;
++ (void)setArray:(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>
+- (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
+
+ at interface NSView : NSObject
+ at end
+
+ at interface NSControl : NSView
+- (void)toggle;
+ at end
+
+ at interface NSViewController<ViewType : NSView *> : NSObject
+ at property (nonatomic,retain) ViewType view;
+ at end
+
+// --------------------------------------------------------------------------
+// Nullability
+// --------------------------------------------------------------------------
+typedef NSControl * _Nonnull Nonnull_NSControl;
+
+ at interface NSNullableTest<ViewType : NSView *> : NSObject
+- (ViewType)view;
+- (nullable ViewType)maybeView;
+ at end
+
+ at interface NSNullableTest2<ViewType : NSView * _Nullable> : NSObject // expected-error{{type parameter 'ViewType' bound 'NSView * _Nullable' cannot explicitly specify nullability}}
+ at end
+
+void test_nullability(void) {
+  NSControl * _Nonnull nonnull_NSControl;
+
+  // Nullability introduced by substitution.
+  NSNullableTest<NSControl *> *unspecifiedControl;
+  nonnull_NSControl = [unspecifiedControl view];
+  nonnull_NSControl = [unspecifiedControl maybeView];  // expected-warning{{from nullable pointer 'NSControl * _Nullable' to non-nullable pointer type 'NSControl * _Nonnull'}}
+
+  // Nullability overridden by substitution.
+  NSNullableTest<Nonnull_NSControl> *nonnullControl;
+  nonnull_NSControl = [nonnullControl view];
+  nonnull_NSControl = [nonnullControl maybeView];  // expected-warning{{from nullable pointer 'Nonnull_NSControl _Nullable' (aka 'NSControl *') to non-nullable pointer type 'NSControl * _Nonnull'}}
+
+  // Nullability cannot be specified directly on a type argument.
+  NSNullableTest<NSControl * _Nonnull> *nonnullControl2; // expected-error{{type argument 'NSControl *' cannot explicitly specify nullability}}
+}
+
+// --------------------------------------------------------------------------
+// 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-warning{{from 'NSString *'}}
+  ip = [mutStringSet firstObject]; // expected-warning{{from 'NSString *'}}
+  ip = [widgetSet firstObject]; // expected-warning{{from 'Widget *'}}
+  ip = [untypedMutSet firstObject]; // expected-warning{{from 'id'}}
+  ip = [mutStringArraySet firstObject]; // expected-warning{{from 'NSArray<NSString *> *'}}
+  ip = [set firstObject]; // expected-warning{{from 'id'}}
+  ip = [mutSet firstObject]; // expected-warning{{from 'id'}}
+  ip = [mutArraySet firstObject]; // expected-warning{{from 'id'}}
+  ip = [block firstObject]; // expected-warning{{from 'id'}}
+
+  ip = [stringSet findObject:@"blah"]; // expected-warning{{from 'NSString *'}}
+
+  // Class messages.
+  ip = [NSSet<NSString *> alloc]; // expected-warning{{from 'NSSet<NSString *> *'}}
+  ip = [NSSet alloc]; // expected-warning{{from 'NSSet *'}}
+  ip = [MutableSetOfArrays<NSString *> alloc]; // expected-warning{{from 'MutableSetOfArrays<NSString *> *'}}
+  ip = [MutableSetOfArrays alloc];  // expected-warning{{from 'MutableSetOfArrays *'}}
+  ip = [NSArray<NSString *> array]; // expected-warning{{from 'NSArray<NSString *> *'}}
+  ip = [NSArray<NSString *><NSCopying> array]; // expected-warning{{from 'NSArray<NSString *> *'}}
+
+  ip = [[NSMutableArray<NSString *> alloc] init];  // expected-warning{{from 'NSMutableArray<NSString *> *'}}
+
+  [[NSMutableArray alloc] initWithArray: stringArray]; // okay
+  [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay
+  [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-warning{{sending 'NSArray<NSString *> *' to parameter of type 'NSArray<NSNumber *> *'}}
+}
+
+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-warning{{parameter of type 'NSString *'}}
+  [widgetSet addObject: window]; // expected-warning{{parameter of type 'Widget *'}}
+  [untypedMutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+  [mutStringArraySet addObject: window]; // expected-warning{{parameter of type 'NSArray<NSString *> *'}}
+  [mutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+  [mutArraySet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+  [block addObject: window]; // expected-warning{{parameter of incompatible 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-warning{{from 'NSArray<NSString *> *'}}
+  ip = mutStringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}}
+  ip = widgetSet.allObjects; // expected-warning{{from 'NSArray<Widget *> *'}}
+  ip = untypedMutSet.allObjects; // expected-warning{{from 'NSArray *'}}
+  ip = mutStringArraySet.allObjects; // expected-warning{{from 'NSArray<NSArray<NSString *> *> *'}}
+  ip = set.allObjects; // expected-warning{{from 'NSArray *'}}
+  ip = mutSet.allObjects; // expected-warning{{from 'NSArray *'}}
+  ip = mutArraySet.allObjects; // expected-warning{{from 'NSArray *'}}
+
+  ip = mutDict.someRandomKey; // expected-warning{{from '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-warning{{to 'NSArray<NSString *> *'}}
+  widgetSet.allObjects = ip; // expected-warning{{to 'NSArray<Widget *> *'}}
+  untypedMutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}}
+  mutStringArraySet.allObjects = ip; // expected-warning{{to 'NSArray<NSArray<NSString *> *> *'}}
+  mutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}}
+  mutArraySet.allObjects = ip; // expected-warning{{to 'NSArray *'}}
+
+  mutDict.someRandomKey = ip; // expected-warning{{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-warning{{from 'NSString *'}}
+
+  ip = mutStringArray[0]; // expected-warning{{from 'NSString *'}}
+  mutStringArray[0] = ip; // expected-warning{{parameter of type 'NSString *'}}
+
+  ip = array[0]; // expected-warning{{from 'id'}}
+
+  ip = mutArray[0]; // expected-warning{{from 'id'}}
+  mutArray[0] = ip; // expected-warning{{parameter of type 'id'}}
+
+  ip = stringWidgetDict[string]; // expected-warning{{from 'Widget *'}}
+  widget = stringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}}
+
+  ip = mutStringWidgetDict[string]; // expected-warning{{from 'Widget *'}}
+  widget = mutStringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}}
+  mutStringWidgetDict[string] = ip; // expected-warning{{to parameter of type 'Widget *'}}
+  mutStringWidgetDict[widget] = widget; // expected-warning{{to parameter of type 'NSString *'}}
+
+  ip = dict[string]; // expected-warning{{from 'id'}}
+
+  ip = mutDict[string]; // expected-warning{{from 'id'}}
+  mutDict[string] = ip; // expected-warning{{to parameter of type 'id'}}
+
+  widget = mutDict[window];
+  mutDict[window] = widget; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Instance variable access.
+// --------------------------------------------------------------------------
+void test_instance_variable(NSArray<NSString *> *stringArray,
+                            NSArray *array) {
+  int *ip;
+
+  ip = stringArray->data; // expected-warning{{from 'NSString **'}}
+  ip = array->data; // expected-warning{{from 'id *'}}
+}
+
+ at implementation WindowArray
+- (void)testInstanceVariable {
+  int *ip;
+
+  ip = data; // expected-warning{{from '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-warning{{incompatible pointer types assigning to 'NSArray<NSString *> *' from 'NSArray<NSNumber *> *'}}
+
+  // Specialized -> specialized (different levels).
+  stringArray = mutStringArray;
+
+  // Specialized -> specialized failure (different levels).
+  numberArray = mutStringArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSNumber *> *' from '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-warning{{from 'NSArray<NSString *> *'}}
+  ip = cond ? mutStringArray : stringArray; // expected-warning{{from 'NSArray<NSString *> *'}}
+
+  ip = cond ? stringArray2 : mutStringArray; // expected-warning{{from 'NSArray<NSString *><NSCopying> *'}}
+  ip = cond ? mutStringArray : stringArray2; // expected-warning{{from 'NSArray<NSString *><NSCopying> *'}}
+
+  ip = cond ? stringArray : mutArray; // FIXME: expected-warning{{from 'NSArray<NSString *> *'}}
+
+  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-warning{{from 'NSString *'}}
+  super.lastObject = ip; // expected-warning{{to 'NSString *'}}
+  ip = [super objectAtIndexedSubscript:0]; // expected-warning{{from 'NSString *'}}
+}
+
++ (void)useSuperMethod {
+  int *ip;
+  ip = super.array; // expected-warning{{from 'NSArray<NSString *> *'}}
+  super.array = ip; // expected-warning{{to 'NSArray<NSString *> *'}}
+  ip = [super array]; // expected-warning{{from 'NSArray<NSString *> *'}}
+}
+ at end

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h?rev=241543&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h Mon Jul  6 22:57:53 2015
@@ -0,0 +1,21 @@
+#pragma clang assume_nonnull begin
+
+__attribute__((objc_root_class))
+ at interface B
+ at end
+
+ at interface C : B
+ at end
+
+__attribute__((objc_root_class))
+ at interface NSGeneric<T : B *> // expected-note{{type parameter 'T' declared here}}
+- (T)tee;
+- (nullable T)maybeTee;
+ at end
+
+typedef NSGeneric<C *> *Generic_with_C;
+
+#pragma clang assume_nonnull end
+
+ at interface NSGeneric<T : C *>(Blah) // expected-error{{type bound 'C *' for type parameter 'T' conflicts with previous bound 'B *'}}
+ at end

Modified: cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm?rev=241543&r1=241542&r2=241543&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm (original)
+++ cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm Mon Jul  6 22:57:53 2015
@@ -2,6 +2,7 @@
 
 #include "nullability-pragmas-1.h"
 #include "nullability-pragmas-2.h"
+#include "nullability-pragmas-generics-1.h"
 
 #if !__has_feature(assume_nonnull)
 #  error assume_nonnull feature is not set
@@ -43,3 +44,14 @@ void test_pragmas_1(A * _Nonnull a, AA *
   ptr = aa->ivar1; // expected-error{{from incompatible type 'id'}}
   ptr = aa->ivar2; // expected-error{{from incompatible type 'id _Nonnull'}}
 }
+
+void test_pragmas_generics(void) {
+  float *fp;
+
+  NSGeneric<C *> *genC;
+  fp = [genC tee]; // expected-error{{from incompatible type 'C *'}}
+  fp = [genC maybeTee]; // expected-error{{from incompatible type 'C * _Nullable'}}
+
+  Generic_with_C genC2;
+  fp = genC2; // expected-error{{from incompatible type 'Generic_with_C' (aka 'NSGeneric<C *> *')}}
+}






More information about the cfe-commits mailing list