Douglas Gregor <[email protected]> writes: > Author: dgregor > Date: Mon Jul 6 22:57:35 2015 > New Revision: 241542 > > URL: http://llvm.org/viewvc/llvm-project?rev=241542&view=rev > Log: > Handle Objective-C type arguments. > > Objective-C type arguments can be provided in angle brackets following > an Objective-C interface type. Syntactically, this is the same > position as one would provide protocol qualifiers (e.g., > id<NSCopying>), so parse both together and let Sema sort out the > ambiguous cases. This applies both when parsing types and when parsing > the superclass of an Objective-C class, which can now be a specialized > type (e.g., NSMutableArray<T> inherits from NSArray<T>). > > Check Objective-C type arguments against the type parameters of the > corresponding class. Verify the length of the type argument list and > that each type argument satisfies the corresponding bound. > > Specializations of parameterized Objective-C classes are represented > in the type system as distinct types. Both specialized types (e.g., > NSArray<NSString *> *) and unspecialized types (NSArray *) are > represented, separately. > > Added: > cfe/trunk/test/Index/annotate-parameterized-classes.m > cfe/trunk/test/SemaObjCXX/parameterized_classes.mm > Modified: > cfe/trunk/include/clang/AST/ASTContext.h > cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h > cfe/trunk/include/clang/AST/DeclObjC.h > cfe/trunk/include/clang/AST/RecursiveASTVisitor.h > cfe/trunk/include/clang/AST/Type.h > cfe/trunk/include/clang/AST/TypeLoc.h > cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > cfe/trunk/include/clang/Parse/Parser.h > cfe/trunk/include/clang/Sema/DeclSpec.h > cfe/trunk/include/clang/Sema/Sema.h > cfe/trunk/lib/AST/ASTContext.cpp > cfe/trunk/lib/AST/ASTDiagnostic.cpp > cfe/trunk/lib/AST/ASTImporter.cpp > cfe/trunk/lib/AST/DeclObjC.cpp > cfe/trunk/lib/AST/Type.cpp > cfe/trunk/lib/AST/TypeLoc.cpp > cfe/trunk/lib/AST/TypePrinter.cpp > cfe/trunk/lib/Parse/ParseDecl.cpp > cfe/trunk/lib/Parse/ParseObjc.cpp > cfe/trunk/lib/Parse/ParseTentative.cpp > cfe/trunk/lib/Sema/DeclSpec.cpp > cfe/trunk/lib/Sema/SemaDeclObjC.cpp > cfe/trunk/lib/Sema/SemaExpr.cpp > cfe/trunk/lib/Sema/SemaExprObjC.cpp > cfe/trunk/lib/Sema/SemaType.cpp > cfe/trunk/lib/Serialization/ASTReader.cpp > cfe/trunk/lib/Serialization/ASTReaderDecl.cpp > cfe/trunk/lib/Serialization/ASTWriter.cpp > cfe/trunk/lib/Serialization/ASTWriterDecl.cpp > cfe/trunk/test/Index/complete-method-decls.m > cfe/trunk/test/PCH/objc_parameterized_classes.m > cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm > cfe/trunk/test/SemaObjC/interface-1.m > cfe/trunk/test/SemaObjC/parameterized_classes.m > cfe/trunk/tools/libclang/CIndex.cpp > cfe/trunk/tools/libclang/CursorVisitor.h > > Modified: cfe/trunk/include/clang/AST/ASTContext.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/ASTContext.h (original) > +++ cfe/trunk/include/clang/AST/ASTContext.h Mon Jul 6 22:57:35 2015 > @@ -236,6 +236,12 @@ class ASTContext : public RefCountedBase > QualType ObjCClassRedefinitionType; > QualType ObjCSelRedefinitionType; > > + /// The identifier 'NSObject'. > + IdentifierInfo *NSObjectName = nullptr; > + > + /// The identifier 'NSCopying'. > + IdentifierInfo *NSCopyingName = nullptr; > + > QualType ObjCConstantStringType; > mutable RecordDecl *CFConstantStringTypeDecl; > > @@ -1189,9 +1195,14 @@ public: > QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, > ObjCInterfaceDecl *PrevDecl = nullptr) const; > > + /// Legacy interface: cannot provide type arguments. > QualType getObjCObjectType(QualType Base, > ObjCProtocolDecl * const *Protocols, > unsigned NumProtocols) const; > + > + QualType getObjCObjectType(QualType Base, > + ArrayRef<QualType> typeArgs, > + ArrayRef<ObjCProtocolDecl *> protocols) const; > > bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl); > /// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in > @@ -1351,6 +1362,24 @@ public: > ObjCSelRedefinitionType = RedefType; > } > > + /// Retrieve the identifier 'NSObject'. > + IdentifierInfo *getNSObjectName() { > + if (!NSObjectName) { > + NSObjectName = &Idents.get("NSObject"); > + } > + > + return NSObjectName; > + } > + > + /// Retrieve the identifier 'NSCopying'. > + IdentifierInfo *getNSCopyingName() { > + if (!NSCopyingName) { > + NSCopyingName = &Idents.get("NSCopying"); > + } > + > + return NSCopyingName; > + } > + > /// \brief Retrieve the Objective-C "instancetype" type, if already known; > /// otherwise, returns a NULL type; > QualType getObjCInstanceType() { > > Modified: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h (original) > +++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h Mon Jul 6 22:57:35 > 2015 > @@ -940,6 +940,8 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, { > // type is itself. > if (T->getBaseType().getTypePtr() != T) > TRY_TO(TraverseType(T->getBaseType())); > + for (auto typeArg : T->getTypeArgsAsWritten()) > + TRY_TO(TraverseType(typeArg)); > }) > > DEF_TRAVERSE_TYPE(ObjCObjectPointerType, > @@ -1166,6 +1168,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, { > // type is itself. > if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) > TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); > + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) > + TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); > }) > > DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, > @@ -1325,7 +1329,10 @@ DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// > for (auto typeParam : *typeParamList) > TRY_TO(TraverseObjCTypeParamDecl(typeParam)); > } > - return true; > + > + if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { > + TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); > + } > }) > > DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement > > Modified: cfe/trunk/include/clang/AST/DeclObjC.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/DeclObjC.h (original) > +++ cfe/trunk/include/clang/AST/DeclObjC.h Mon Jul 6 22:57:35 2015 > @@ -794,9 +794,9 @@ class ObjCInterfaceDecl : public ObjCCon > /// declaration. > ObjCInterfaceDecl *Definition; > > - /// Class's super class. > - ObjCInterfaceDecl *SuperClass; > - > + /// When non-null, this is always an ObjCObjectType. > + TypeSourceInfo *SuperClassTInfo; > + > /// Protocols referenced in the \@interface declaration > ObjCProtocolList ReferencedProtocols; > > @@ -837,16 +837,13 @@ class ObjCInterfaceDecl : public ObjCCon > }; > /// One of the \c InheritedDesignatedInitializersState enumeratos. > mutable unsigned InheritedDesignatedInitializers : 2; > - > - /// \brief The location of the superclass, if any. > - SourceLocation SuperClassLoc; > > /// \brief The location of the last location in this declaration, before > /// the properties/methods. For example, this will be the '>', '}', or > /// identifier, > SourceLocation EndLoc; > > - DefinitionData() : Definition(), SuperClass(), CategoryList(), > IvarList(), > + DefinitionData() : Definition(), SuperClassTInfo(), CategoryList(), > IvarList(), > ExternallyCompleted(), > IvarListMissingImplementation(true), > HasDesignatedInitializers(), > @@ -903,8 +900,8 @@ public: > /// Retrieve the type parameters of this class. > /// > /// This function looks for a type parameter list for the given > - /// class; if the class has been declared (with @class) but not > - /// defined (with @interface), it will search for a declaration that > + /// class; if the class has been declared (with \c \@class) but not > + /// defined (with \c \@interface), it will search for a declaration that > /// has type parameters, skipping any declarations that do not. > ObjCTypeParamList *getTypeParamList() const; > > @@ -1160,7 +1157,16 @@ public: > /// a forward declaration (\@class) to a definition (\@interface). > void startDefinition(); > > - ObjCInterfaceDecl *getSuperClass() const { > + /// Retrieve the superclass type. > + const ObjCObjectType *getSuperClassType() const { > + if (TypeSourceInfo *TInfo = getSuperClassTInfo()) > + return TInfo->getType()->castAs<ObjCObjectType>(); > + > + return nullptr; > + } > + > + // Retrieve the type source information for the superclass. > + TypeSourceInfo *getSuperClassTInfo() const { > // FIXME: Should make sure no callers ever do this. > if (!hasDefinition()) > return nullptr; > @@ -1168,13 +1174,15 @@ public: > if (data().ExternallyCompleted) > LoadExternalDefinition(); > > - return data().SuperClass; > + return data().SuperClassTInfo; > } > > - void setSuperClass(ObjCInterfaceDecl * superCls) { > - data().SuperClass = > - (superCls && superCls->hasDefinition()) ? superCls->getDefinition() > - : superCls; > + // Retrieve the declaration for the superclass of this class, which > + // does not include any type arguments that apply to the superclass. > + ObjCInterfaceDecl *getSuperClass() const; > + > + void setSuperClass(TypeSourceInfo *superClass) { > + data().SuperClassTInfo = superClass; > } > > /// \brief Iterator that walks over the list of categories, filtering out > @@ -1466,8 +1474,8 @@ public: > > void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; } > > - void setSuperClassLoc(SourceLocation Loc) { data().SuperClassLoc = Loc; } > - SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; } > + /// Retrieve the starting location of the superclass. > + SourceLocation getSuperClassLoc() const; > > /// isImplicitInterfaceDecl - check that this is an implicitly declared > /// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation > > Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) > +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Mon Jul 6 22:57:35 2015 > @@ -1008,6 +1008,8 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, { > // type is itself. > if (T->getBaseType().getTypePtr() != T) > TRY_TO(TraverseType(T->getBaseType())); > + for (auto typeArg : T->getTypeArgsAsWritten()) > + TRY_TO(TraverseType(typeArg)); > }) > > DEF_TRAVERSE_TYPE(ObjCObjectPointerType, > @@ -1234,6 +1236,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, { > // type is itself. > if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) > TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); > + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) > + TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); > }) > > DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, > @@ -1399,6 +1403,10 @@ DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// > for (auto typeParam : *typeParamList) > TRY_TO(TraverseObjCTypeParamDecl(typeParam)); > } > + > + if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { > + TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); > + } > }) > > DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement > > Modified: cfe/trunk/include/clang/AST/Type.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/Type.h (original) > +++ cfe/trunk/include/clang/AST/Type.h Mon Jul 6 22:57:35 2015 > @@ -1288,10 +1288,14 @@ protected: > > unsigned : NumTypeBits; > > + /// The number of type arguments stored directly on this object type. > + unsigned NumTypeArgs : 7; > + > /// NumProtocols - The number of protocols stored directly on this > /// object type. > - unsigned NumProtocols : 32 - NumTypeBits; > + unsigned NumProtocols : 7; > }; > + static_assert(NumTypeBits + 7 + 7 <= 32, "Does not fit in an unsigned"); > > class ReferenceTypeBitfields { > friend class ReferenceType; > @@ -1586,6 +1590,7 @@ public: > bool isObjCObjectOrInterfaceType() const; > bool isObjCIdType() const; // id > bool isObjCClassType() const; // Class > + bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; > bool isObjCSelType() const; // Class > bool isObjCBuiltinType() const; // 'id' or 'Class' > bool isObjCARCBridgableType() const; > @@ -4369,19 +4374,25 @@ public: > }; > > /// ObjCObjectType - Represents a class type in Objective C. > -/// Every Objective C type is a combination of a base type and a > -/// list of protocols. > +/// > +/// Every Objective C type is a combination of a base type, a set of > +/// type arguments (optional, for parameterized classes) and a list of > +/// protocols. > /// > /// Given the following declarations: > /// \code > -/// \@class C; > +/// \@class C<T>; > /// \@protocol P; > /// \endcode > /// > /// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType > /// with base C and no protocols. > /// > -/// 'C<P>' is an ObjCObjectType with base C and protocol list [P]. > +/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list > [P]. > +/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no > +/// protocol list. > +/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments > 'C*', > +/// and protocol list [P]. > /// > /// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose > /// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType > @@ -4391,8 +4402,10 @@ public: > /// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually > /// this should get its own sugar class to better represent the source. > class ObjCObjectType : public Type { > - // ObjCObjectType.NumProtocols - the number of protocols stored > + // ObjCObjectType.NumTypeArgs - the number of type arguments stored > // after the ObjCObjectPointerType node. > + // ObjCObjectType.NumProtocols - the number of protocols stored > + // after the type arguments of ObjCObjectPointerType node. > // > // These protocols are those written directly on the type. If > // protocol qualifiers ever become additive, the iterators will need > @@ -4408,17 +4421,24 @@ class ObjCObjectType : public Type { > return const_cast<ObjCObjectType*>(this)->getProtocolStorage(); > } > > + QualType *getTypeArgStorage(); > + const QualType *getTypeArgStorage() const { > + return const_cast<ObjCObjectType *>(this)->getTypeArgStorage(); > + } > + > ObjCProtocolDecl **getProtocolStorage(); > > protected: > ObjCObjectType(QualType Canonical, QualType Base, > - ObjCProtocolDecl * const *Protocols, unsigned NumProtocols); > + ArrayRef<QualType> typeArgs, > + ArrayRef<ObjCProtocolDecl *> protocols); > > enum Nonce_ObjCInterface { Nonce_ObjCInterface }; > ObjCObjectType(enum Nonce_ObjCInterface) > : Type(ObjCInterface, QualType(), false, false, false, false), > BaseType(QualType(this_(), 0)) { > ObjCObjectTypeBits.NumProtocols = 0; > + ObjCObjectTypeBits.NumTypeArgs = 0; > } > > public: > @@ -4452,6 +4472,33 @@ public: > /// really is an interface. > ObjCInterfaceDecl *getInterface() const; > > + /// Determine whether this object type is "specialized", meaning > + /// that it has type arguments. > + bool isSpecialized() const; > + > + /// Determine whether this object type was written with type arguments. > + bool isSpecializedAsWritten() const { > + return ObjCObjectTypeBits.NumTypeArgs > 0; > + } > + > + /// Determine whether this object type is "unspecialized", meaning > + /// that it has no type arguments. > + bool isUnspecialized() const { return !isSpecialized(); } > + > + /// Determine whether this object type is "unspecialized" as > + /// written, meaning that it has no type arguments. > + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } > + > + /// Retrieve the type arguments of this object type (semantically). > + ArrayRef<QualType> getTypeArgs() const; > + > + /// Retrieve the type arguments of this object type as they were > + /// written. > + ArrayRef<QualType> getTypeArgsAsWritten() const { > + return ArrayRef<QualType>(getTypeArgStorage(), > + ObjCObjectTypeBits.NumTypeArgs); > + } > + > typedef ObjCProtocolDecl * const *qual_iterator; > typedef llvm::iterator_range<qual_iterator> qual_range; > > @@ -4491,21 +4538,25 @@ class ObjCObjectTypeImpl : public ObjCOb > // will need to be modified. > > ObjCObjectTypeImpl(QualType Canonical, QualType Base, > - ObjCProtocolDecl * const *Protocols, > - unsigned NumProtocols) > - : ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {} > + ArrayRef<QualType> typeArgs, > + ArrayRef<ObjCProtocolDecl *> protocols) > + : ObjCObjectType(Canonical, Base, typeArgs, protocols) {} > > public: > void Profile(llvm::FoldingSetNodeID &ID); > static void Profile(llvm::FoldingSetNodeID &ID, > QualType Base, > - ObjCProtocolDecl *const *protocols, > - unsigned NumProtocols); > + ArrayRef<QualType> typeArgs, > + ArrayRef<ObjCProtocolDecl *> protocols); > }; > > +inline QualType *ObjCObjectType::getTypeArgStorage() { > + return reinterpret_cast<QualType > *>(static_cast<ObjCObjectTypeImpl*>(this)+1); > +} > + > inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() { > - return reinterpret_cast<ObjCProtocolDecl**>( > - static_cast<ObjCObjectTypeImpl*>(this) + 1); > + return reinterpret_cast<ObjCProtocolDecl**>( > + getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); > } > > /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for > @@ -4556,9 +4607,14 @@ public: > }; > > inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { > - if (const ObjCInterfaceType *T = > - getBaseType()->getAs<ObjCInterfaceType>()) > - return T->getDecl(); > + QualType baseType = getBaseType(); > + while (const ObjCObjectType *ObjT = baseType->getAs<ObjCObjectType>()) { > + if (const ObjCInterfaceType *T = dyn_cast<ObjCInterfaceType>(ObjT)) > + return T->getDecl(); > + > + baseType = ObjT->getBaseType(); > + } > + > return nullptr; > } > > @@ -4653,6 +4709,31 @@ public: > return getObjectType()->isObjCQualifiedClass(); > } > > + /// Whether this type is specialized, meaning that it has type arguments. > + bool isSpecialized() const { return getObjectType()->isSpecialized(); } > + > + /// Whether this type is specialized, meaning that it has type arguments. > + bool isSpecializedAsWritten() const { > + return getObjectType()->isSpecializedAsWritten(); > + } > + > + /// Whether this type is unspecialized, meaning that is has no type > arguments. > + bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } > + > + /// Determine whether this object type is "unspecialized" as > + /// written, meaning that it has no type arguments. > + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } > + > + /// Retrieve the type arguments for this type. > + ArrayRef<QualType> getTypeArgs() const { > + return getObjectType()->getTypeArgs(); > + } > + > + /// Retrieve the type arguments for this type. > + ArrayRef<QualType> getTypeArgsAsWritten() const { > + return getObjectType()->getTypeArgsAsWritten(); > + } > + > /// An iterator over the qualifiers on the object type. Provided > /// for convenience. This will always iterate over the full set of > /// protocols on a type, not just those provided directly. > > Modified: cfe/trunk/include/clang/AST/TypeLoc.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeLoc.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/TypeLoc.h (original) > +++ cfe/trunk/include/clang/AST/TypeLoc.h Mon Jul 6 22:57:35 2015 > @@ -799,9 +799,11 @@ public: > }; > > > -struct ObjCProtocolListLocInfo { > - SourceLocation LAngleLoc; > - SourceLocation RAngleLoc; > +struct ObjCObjectTypeLocInfo { > + SourceLocation TypeArgsLAngleLoc; > + SourceLocation TypeArgsRAngleLoc; > + SourceLocation ProtocolLAngleLoc; > + SourceLocation ProtocolRAngleLoc; > bool HasBaseTypeAsWritten; > }; > > @@ -813,25 +815,59 @@ struct ObjCProtocolListLocInfo { > class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, > ObjCObjectTypeLoc, > ObjCObjectType, > - ObjCProtocolListLocInfo> { > - // SourceLocations are stored after Info, one for each Protocol. > + ObjCObjectTypeLocInfo> { > + // TypeSourceInfo*'s are stored after Info, one for each type argument. > + TypeSourceInfo **getTypeArgLocArray() const { > + return (TypeSourceInfo**)this->getExtraLocalData(); > + } > + > + // SourceLocations are stored after the type argument information, one for > + // each Protocol. > SourceLocation *getProtocolLocArray() const { > - return (SourceLocation*) this->getExtraLocalData(); > + return (SourceLocation*)(getTypeArgLocArray() + getNumTypeArgs()); > } > > public: > - SourceLocation getLAngleLoc() const { > - return this->getLocalData()->LAngleLoc; > + SourceLocation getTypeArgsLAngleLoc() const { > + return this->getLocalData()->TypeArgsLAngleLoc; > + } > + void setTypeArgsLAngleLoc(SourceLocation Loc) { > + this->getLocalData()->TypeArgsLAngleLoc = Loc; > + } > + > + SourceLocation getTypeArgsRAngleLoc() const { > + return this->getLocalData()->TypeArgsRAngleLoc; > + } > + void setTypeArgsRAngleLoc(SourceLocation Loc) { > + this->getLocalData()->TypeArgsRAngleLoc = Loc; > } > - void setLAngleLoc(SourceLocation Loc) { > - this->getLocalData()->LAngleLoc = Loc; > + > + unsigned getNumTypeArgs() const { > + return this->getTypePtr()->getTypeArgsAsWritten().size(); > } > > - SourceLocation getRAngleLoc() const { > - return this->getLocalData()->RAngleLoc; > + TypeSourceInfo *getTypeArgTInfo(unsigned i) const { > + assert(i < getNumTypeArgs() && "Index is out of bounds!"); > + return getTypeArgLocArray()[i]; > } > - void setRAngleLoc(SourceLocation Loc) { > - this->getLocalData()->RAngleLoc = Loc; > + > + void setTypeArgTInfo(unsigned i, TypeSourceInfo *TInfo) { > + assert(i < getNumTypeArgs() && "Index is out of bounds!"); > + getTypeArgLocArray()[i] = TInfo; > + } > + > + SourceLocation getProtocolLAngleLoc() const { > + return this->getLocalData()->ProtocolLAngleLoc; > + } > + void setProtocolLAngleLoc(SourceLocation Loc) { > + this->getLocalData()->ProtocolLAngleLoc = Loc; > + } > + > + SourceLocation getProtocolRAngleLoc() const { > + return this->getLocalData()->ProtocolRAngleLoc; > + } > + void setProtocolRAngleLoc(SourceLocation Loc) { > + this->getLocalData()->ProtocolRAngleLoc = Loc; > } > > unsigned getNumProtocols() const { > @@ -865,23 +901,26 @@ public: > } > > SourceRange getLocalSourceRange() const { > - return SourceRange(getLAngleLoc(), getRAngleLoc()); > + SourceLocation start = getTypeArgsLAngleLoc(); > + if (start.isInvalid()) > + start = getProtocolLAngleLoc(); > + SourceLocation end = getProtocolRAngleLoc(); > + if (end.isInvalid()) > + end = getTypeArgsRAngleLoc(); > + return SourceRange(start, end); > } > > - void initializeLocal(ASTContext &Context, SourceLocation Loc) { > - setHasBaseTypeAsWritten(true); > - setLAngleLoc(Loc); > - setRAngleLoc(Loc); > - for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) > - setProtocolLoc(i, Loc); > - } > + void initializeLocal(ASTContext &Context, SourceLocation Loc); > > unsigned getExtraLocalDataSize() const { > - return this->getNumProtocols() * sizeof(SourceLocation); > + return this->getNumTypeArgs() * sizeof(TypeSourceInfo *) > + + this->getNumProtocols() * sizeof(SourceLocation); > } > > unsigned getExtraLocalDataAlignment() const { > - return llvm::alignOf<SourceLocation>(); > + static_assert(alignof(ObjCObjectTypeLoc) >= alignof(TypeSourceInfo *), > + "not enough alignment for tail-allocated data"); > + return llvm::alignOf<TypeSourceInfo *>(); > } > > QualType getInnerType() const { > > Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Jul 6 22:57:35 > 2015 > @@ -1022,12 +1022,11 @@ let CategoryName = "Generics Issue" in { > def err_objc_expected_type_parameter : Error< > "expected type parameter name">; > > -def err_objc_parameterized_class_without_base : Error< > - "parameterized Objective-C class %0 must have a superclass">; > - > def err_objc_parameterized_implementation : Error< > "@implementation cannot have type parameters">; > > +def err_objc_type_args_after_protocols : Error< > + "protocol qualifiers must precede type arguments">; > } > > } // end of Parser diagnostics > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul 6 22:57:35 > 2015 > @@ -7780,6 +7780,36 @@ def err_objc_parameterized_forward_class > def err_objc_parameterized_forward_class_first : Error< > "class %0 previously declared with type parameters">; > > +def err_objc_type_arg_missing_star : Error< > + "type argument %0 must be a pointer (requires a '*')">; > + > +def err_objc_type_arg_missing : Error< > + "no type or protocol named %0">; > + > +def err_objc_protocol_suggest : Error< > + "no protocol named %0: did you mean %1?">; > + > +def err_objc_type_args_and_protocols : Error< > + "angle brackets contain both a %select{type|protocol}0 (%1) and a " > + "%select{protocol|type}0 (%2)">; > + > +def err_objc_type_args_non_class : Error< > + "type arguments cannot be applied to non-class type %0">; > + > +def err_objc_type_args_non_parameterized_class : Error< > + "type arguments cannot be applied to non-parameterized class %0">; > + > +def err_objc_type_args_specialized_class : Error< > + "type arguments cannot be applied to already-specialized class type %0">; > + > +def err_objc_type_args_wrong_arity : Error< > + "too %select{many|few}0 type arguments for class %1 (have %2, expected > %3)">; > } > > +def err_objc_type_arg_not_id_compatible : Error< > + "type argument %0 is neither an Objective-C object nor a block type">; > + > +def err_objc_type_arg_does_not_match_bound : Error< > + "type argument %0 does not satisy the bound (%1) of type parameter %2">; > + > } // end of sema component. > > Modified: cfe/trunk/include/clang/Parse/Parser.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Parse/Parser.h (original) > +++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul 6 22:57:35 2015 > @@ -1269,6 +1269,8 @@ private: > SourceLocation &LAngleLoc, > SourceLocation &EndProtoLoc); > bool ParseObjCProtocolQualifiers(DeclSpec &DS); > + void ParseObjCTypeArgsOrProtocolQualifiers(DeclSpec &DS, > + bool warnOnIncompleteProtocols); > void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, > Decl *CDecl); > DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, > > Modified: cfe/trunk/include/clang/Sema/DeclSpec.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Sema/DeclSpec.h (original) > +++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Jul 6 22:57:35 2015 > @@ -373,6 +373,14 @@ private: > // Scope specifier for the type spec, if applicable. > CXXScopeSpec TypeScope; > > + /// List of Objective-C type arguments, e.g., in \c NSArray<NSView *>. > + ArrayRef<ParsedType> ObjCTypeArgs; > + > + /// Location of the '<' that starts a list of Objective-C type arguments. > + SourceLocation ObjCTypeArgsLAngleLoc; > + /// Location of the '>' that ends a list of Objective-C type arguments. > + SourceLocation ObjCTypeArgsRAngleLoc; > + > // List of protocol qualifiers for objective-c classes. Used for > // protocol-qualified interfaces "NString<foo>" and protocol-qualified id > // "id<foo>". > @@ -449,6 +457,7 @@ public: > ObjCQualifiers(nullptr) { > } > ~DeclSpec() { > + delete [] ObjCTypeArgs.data(); > delete [] ProtocolQualifiers; > delete [] ProtocolLocs; > } > @@ -751,6 +760,25 @@ public: > Attrs.takeAllFrom(attrs); > } > > + /// Determine whether the declaration specifiers contain Objective-C > + /// type arguments. > + bool hasObjCTypeArgs() const { return !ObjCTypeArgs.empty(); } > + > + ArrayRef<ParsedType> getObjCTypeArgs() const { return ObjCTypeArgs; } > + SourceLocation getObjCTypeArgsLAngleLoc() const { > + return ObjCTypeArgsLAngleLoc; > + } > + SourceLocation getObjCTypeArgsRAngleLoc() const { > + return ObjCTypeArgsRAngleLoc; > + } > + SourceRange getObjCTypeArgsRange() const { > + return SourceRange(ObjCTypeArgsLAngleLoc, ObjCTypeArgsRAngleLoc); > + } > + > + void setObjCTypeArgs(SourceLocation lAngleLoc, > + ArrayRef<ParsedType> args, > + SourceLocation rAngleLoc); > + > typedef Decl * const *ProtocolQualifierListTy; > ProtocolQualifierListTy getProtocolQualifiers() const { > return ProtocolQualifiers; > > Modified: cfe/trunk/include/clang/Sema/Sema.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Sema/Sema.h (original) > +++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul 6 22:57:35 2015 > @@ -7098,17 +7098,30 @@ public: > SourceLocation rAngleLoc); > void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); > > - Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc, > + Decl *ActOnStartClassInterface(Scope *S, > + SourceLocation AtInterfaceLoc, > IdentifierInfo *ClassName, > SourceLocation ClassLoc, > ObjCTypeParamList *typeParamList, > IdentifierInfo *SuperName, > SourceLocation SuperLoc, > + ArrayRef<ParsedType> SuperTypeArgs, > + SourceRange SuperTypeArgsRange, > Decl * const *ProtoRefs, > unsigned NumProtoRefs, > const SourceLocation *ProtoLocs, > SourceLocation EndProtoLoc, > AttributeList *AttrList); > + > + void ActOnSuperClassOfClassInterface(Scope *S, > + SourceLocation AtInterfaceLoc, > + ObjCInterfaceDecl *IDecl, > + IdentifierInfo *ClassName, > + SourceLocation ClassLoc, > + IdentifierInfo *SuperName, > + SourceLocation SuperLoc, > + ArrayRef<ParsedType> SuperTypeArgs, > + SourceRange SuperTypeArgsRange); > > void ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs, > IdentifierInfo *SuperName, > @@ -7174,6 +7187,19 @@ public: > unsigned NumProtocols, > SmallVectorImpl<Decl *> &Protocols); > > + /// Given a list of identifiers (and their locations), resolve the > + /// names to either Objective-C protocol qualifiers or type > + /// arguments, as appropriate. The result will be attached to the > + /// given declaration specifiers. > + void actOnObjCTypeArgsOrProtocolQualifiers( > + Scope *S, > + DeclSpec &DS, > + SourceLocation lAngleLoc, > + ArrayRef<IdentifierInfo *> identifiers, > + ArrayRef<SourceLocation> identifierLocs, > + SourceLocation rAngleLoc, > + bool warnOnIncompleteProtocols); > + > /// Ensure attributes are consistent with type. > /// \param [in, out] Attributes The attributes to check; they will > /// be modified to be consistent with \p PropertyTy. > > Modified: cfe/trunk/lib/AST/ASTContext.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/ASTContext.cpp (original) > +++ cfe/trunk/lib/AST/ASTContext.cpp Mon Jul 6 22:57:35 2015 > @@ -3618,45 +3618,85 @@ static void SortAndUniqueProtocols(ObjCP > QualType ASTContext::getObjCObjectType(QualType BaseType, > ObjCProtocolDecl * const *Protocols, > unsigned NumProtocols) const { > - // If the base type is an interface and there aren't any protocols > - // to add, then the interface type will do just fine. > - if (!NumProtocols && isa<ObjCInterfaceType>(BaseType)) > - return BaseType; > + return getObjCObjectType(BaseType, { }, > + llvm::makeArrayRef(Protocols, NumProtocols)); > +} > + > +QualType ASTContext::getObjCObjectType( > + QualType baseType, > + ArrayRef<QualType> typeArgs, > + ArrayRef<ObjCProtocolDecl *> protocols) const { > + // If the base type is an interface and there aren't any protocols or > + // type arguments to add, then the interface type will do just fine. > + if (typeArgs.empty() && protocols.empty() && > isa<ObjCInterfaceType>(baseType)) > + return baseType; > > // Look in the folding set for an existing type. > llvm::FoldingSetNodeID ID; > - ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols); > + ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols); > void *InsertPos = nullptr; > if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, > InsertPos)) > return QualType(QT, 0); > > - // Build the canonical type, which has the canonical base type and > - // a sorted-and-uniqued list of protocols. > - QualType Canonical; > - bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols); > - if (!ProtocolsSorted || !BaseType.isCanonical()) { > - if (!ProtocolsSorted) { > - SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, > - Protocols + > NumProtocols); > - unsigned UniqueCount = NumProtocols; > - > - SortAndUniqueProtocols(&Sorted[0], UniqueCount); > - Canonical = getObjCObjectType(getCanonicalType(BaseType), > - &Sorted[0], UniqueCount); > + // Determine the type arguments to be used for canonicalization, > + // which may be explicitly specified here or written on the base > + // type. > + ArrayRef<QualType> effectiveTypeArgs = typeArgs; > + if (effectiveTypeArgs.empty()) { > + if (auto baseObject = baseType->getAs<ObjCObjectType>()) > + effectiveTypeArgs = baseObject->getTypeArgs(); > + } > + > + // Build the canonical type, which has the canonical base type and a > + // sorted-and-uniqued list of protocols and the type arguments > + // canonicalized. > + QualType canonical; > + bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(), > + effectiveTypeArgs.end(), > + [&](QualType type) { > + return type.isCanonical(); > + }); > + bool protocolsSorted = areSortedAndUniqued(protocols.data(), > + protocols.size()); > + if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) { > + // Determine the canonical type arguments. > + ArrayRef<QualType> canonTypeArgs; > + SmallVector<QualType, 4> canonTypeArgsVec; > + if (!typeArgsAreCanonical) { > + canonTypeArgsVec.reserve(effectiveTypeArgs.size()); > + for (auto typeArg : effectiveTypeArgs) > + canonTypeArgsVec.push_back(getCanonicalType(typeArg)); > + canonTypeArgs = canonTypeArgsVec; > } else { > - Canonical = getObjCObjectType(getCanonicalType(BaseType), > - Protocols, NumProtocols); > + canonTypeArgs = effectiveTypeArgs; > } > > + ArrayRef<ObjCProtocolDecl *> canonProtocols; > + SmallVector<ObjCProtocolDecl*, 8> canonProtocolsVec; > + if (!protocolsSorted) { > + canonProtocolsVec.insert(canonProtocolsVec.begin(), > + protocols.begin(), > + protocols.end()); > + unsigned uniqueCount = protocols.size(); > + SortAndUniqueProtocols(&canonProtocolsVec[0], uniqueCount); > + canonProtocols = llvm::makeArrayRef(&canonProtocolsVec[0], > uniqueCount); > + } else { > + canonProtocols = protocols; > + } > + > + canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs, > + canonProtocols); > + > // Regenerate InsertPos. > ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos); > } > > - unsigned Size = sizeof(ObjCObjectTypeImpl); > - Size += NumProtocols * sizeof(ObjCProtocolDecl *); > - void *Mem = Allocate(Size, TypeAlignment); > + unsigned size = sizeof(ObjCObjectTypeImpl); > + size += typeArgs.size() * sizeof(QualType); > + size += protocols.size() * sizeof(ObjCProtocolDecl *); > + void *mem = Allocate(size, TypeAlignment); > ObjCObjectTypeImpl *T = > - new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, > NumProtocols); > + new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols); > > Types.push_back(T); > ObjCObjectTypes.InsertNode(T, InsertPos); > @@ -5921,7 +5961,7 @@ void ASTContext::getObjCEncodingForTypeQ > > TypedefDecl *ASTContext::getObjCIdDecl() const { > if (!ObjCIdDecl) { > - QualType T = getObjCObjectType(ObjCBuiltinIdTy, nullptr, 0); > + QualType T = getObjCObjectType(ObjCBuiltinIdTy, { }, { }); > T = getObjCObjectPointerType(T); > ObjCIdDecl = buildImplicitTypedef(T, "id"); > } > @@ -5938,7 +5978,7 @@ TypedefDecl *ASTContext::getObjCSelDecl( > > TypedefDecl *ASTContext::getObjCClassDecl() const { > if (!ObjCClassDecl) { > - QualType T = getObjCObjectType(ObjCBuiltinClassTy, nullptr, 0); > + QualType T = getObjCObjectType(ObjCBuiltinClassTy, { }, { }); > T = getObjCObjectPointerType(T); > ObjCClassDecl = buildImplicitTypedef(T, "Class"); > } > > Modified: cfe/trunk/lib/AST/ASTDiagnostic.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDiagnostic.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/ASTDiagnostic.cpp (original) > +++ cfe/trunk/lib/AST/ASTDiagnostic.cpp Mon Jul 6 22:57:35 2015 > @@ -125,12 +125,22 @@ break; \ > if (const PointerType *Ty = QT->getAs<PointerType>()) { > QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), > ShouldAKA)); > + } else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) { > + QT = Context.getObjCObjectPointerType(Desugar(Context, > Ty->getPointeeType(), > + ShouldAKA)); > } else if (const LValueReferenceType *Ty = > QT->getAs<LValueReferenceType>()) { > QT = Context.getLValueReferenceType(Desugar(Context, > Ty->getPointeeType(), > ShouldAKA)); > } else if (const RValueReferenceType *Ty = > QT->getAs<RValueReferenceType>()) { > QT = Context.getRValueReferenceType(Desugar(Context, > Ty->getPointeeType(), > ShouldAKA)); > + } else if (const auto *Ty = QT->getAs<ObjCObjectType>()) { > + if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) {
According to ubsan, ShouldAKA is evaluated uninitialized here. In fact, only one of the two non-recursive callers bother initializing it, but until now we never read the value within Desugar. I've gone ahead and fixed this in r241705. Please take a look. > + QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA); > + QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(), > + llvm::makeArrayRef(Ty->qual_begin(), > + > Ty->getNumProtocols())); > + } > } > > return QC.apply(Context, QT); > > Modified: cfe/trunk/lib/AST/ASTImporter.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/ASTImporter.cpp (original) > +++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Jul 6 22:57:35 2015 > @@ -1844,6 +1844,16 @@ QualType ASTNodeImporter::VisitObjCObjec > if (ToBaseType.isNull()) > return QualType(); > > + SmallVector<QualType, 4> TypeArgs; > + for (auto TypeArg : T->getTypeArgs()) { > + QualType ImportedTypeArg = Importer.Import(TypeArg); > + if (ImportedTypeArg.isNull()) > + return QualType(); > + > + TypeArgs.push_back(ImportedTypeArg); > + } > + > + > SmallVector<ObjCProtocolDecl *, 4> Protocols; > for (auto *P : T->quals()) { > ObjCProtocolDecl *Protocol > @@ -1853,9 +1863,8 @@ QualType ASTNodeImporter::VisitObjCObjec > Protocols.push_back(Protocol); > } > > - return Importer.getToContext().getObjCObjectType(ToBaseType, > - Protocols.data(), > - Protocols.size()); > + return Importer.getToContext().getObjCObjectType(ToBaseType, TypeArgs, > + Protocols); > } > > QualType > @@ -3694,13 +3703,11 @@ bool ASTNodeImporter::ImportDefinition(O > > // If this class has a superclass, import it. > if (From->getSuperClass()) { > - ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>( > - Importer.Import(From->getSuperClass())); > - if (!Super) > + TypeSourceInfo *SuperTInfo = Importer.Import(From->getSuperClassTInfo()); > + if (!SuperTInfo) > return true; > - > - To->setSuperClass(Super); > - To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc())); > + > + To->setSuperClass(SuperTInfo); > } > > // Import protocols > @@ -5367,7 +5374,7 @@ TypeSourceInfo *ASTImporter::Import(Type > return nullptr; > > return ToContext.getTrivialTypeSourceInfo(T, > - FromTSI->getTypeLoc().getLocStart()); > + Import(FromTSI->getTypeLoc().getLocStart())); > } > > Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) { > > Modified: cfe/trunk/lib/AST/DeclObjC.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/DeclObjC.cpp (original) > +++ cfe/trunk/lib/AST/DeclObjC.cpp Mon Jul 6 22:57:35 2015 > @@ -259,6 +259,33 @@ ObjCTypeParamList *ObjCInterfaceDecl::ge > return nullptr; > } > > +ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const { > + // FIXME: Should make sure no callers ever do this. > + if (!hasDefinition()) > + return nullptr; > + > + if (data().ExternallyCompleted) > + LoadExternalDefinition(); > + > + if (const ObjCObjectType *superType = getSuperClassType()) { > + if (ObjCInterfaceDecl *superDecl = superType->getInterface()) { > + if (ObjCInterfaceDecl *superDef = superDecl->getDefinition()) > + return superDef; > + > + return superDecl; > + } > + } > + > + return nullptr; > +} > + > +SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const { > + if (TypeSourceInfo *superTInfo = getSuperClassTInfo()) > + return superTInfo->getTypeLoc().getLocStart(); > + > + return SourceLocation(); > +} > + > /// FindPropertyVisibleInPrimaryClass - Finds declaration of the property > /// with name 'PropertyId' in the primary class; including those in protocols > /// (direct or indirect) used by the primary class. > > Modified: cfe/trunk/lib/AST/Type.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/Type.cpp (original) > +++ cfe/trunk/lib/AST/Type.cpp Mon Jul 6 22:57:35 2015 > @@ -467,19 +467,56 @@ const RecordType *Type::getAsUnionType() > } > > ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, > - ObjCProtocolDecl * const *Protocols, > - unsigned NumProtocols) > + ArrayRef<QualType> typeArgs, > + ArrayRef<ObjCProtocolDecl *> protocols) > : Type(ObjCObject, Canonical, false, false, false, false), > BaseType(Base) > { > - ObjCObjectTypeBits.NumProtocols = NumProtocols; > - assert(getNumProtocols() == NumProtocols && > + ObjCObjectTypeBits.NumTypeArgs = typeArgs.size(); > + assert(getTypeArgsAsWritten().size() == typeArgs.size() && > + "bitfield overflow in type argument count"); > + ObjCObjectTypeBits.NumProtocols = protocols.size(); > + assert(getNumProtocols() == protocols.size() && > "bitfield overflow in protocol count"); > - if (NumProtocols) > - memcpy(getProtocolStorage(), Protocols, > - NumProtocols * sizeof(ObjCProtocolDecl*)); > + if (!typeArgs.empty()) > + memcpy(getTypeArgStorage(), typeArgs.data(), > + typeArgs.size() * sizeof(QualType)); > + if (!protocols.empty()) > + memcpy(getProtocolStorage(), protocols.data(), > + protocols.size() * sizeof(ObjCProtocolDecl*)); > } > > +bool ObjCObjectType::isSpecialized() const { > + // If we have type arguments written here, the type is specialized. > + if (ObjCObjectTypeBits.NumTypeArgs > 0) > + return true; > + > + if (!qual_empty()) { > + // Otherwise, check whether the base type is specialized. > + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) > + return objcObject->isSpecialized(); > + } > + > + // Not specialized. > + return false; > +} > + > +ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { > + // We have type arguments written on this type. > + if (isSpecializedAsWritten()) > + return getTypeArgsAsWritten(); > + > + if (!qual_empty()) { > + // Look at the base type, which might have type arguments. > + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) > + return objcObject->getTypeArgs(); > + } > + > + // No type arguments. > + return { }; > +} > + > + > const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { > // There is no sugar for ObjCObjectType's, just return the canonical > // type pointer if it is the right class. There is no typedef information > to > @@ -2076,15 +2113,20 @@ QualifierCollector::apply(const ASTConte > > void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID, > QualType BaseType, > - ObjCProtocolDecl * const *Protocols, > - unsigned NumProtocols) { > + ArrayRef<QualType> typeArgs, > + ArrayRef<ObjCProtocolDecl *> protocols) { > ID.AddPointer(BaseType.getAsOpaquePtr()); > - for (unsigned i = 0; i != NumProtocols; i++) > - ID.AddPointer(Protocols[i]); > + ID.AddInteger(typeArgs.size()); > + for (auto typeArg : typeArgs) > + ID.AddPointer(typeArg.getAsOpaquePtr()); > + ID.AddInteger(protocols.size()); > + for (auto proto : protocols) > + ID.AddPointer(proto); > } > > void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { > - Profile(ID, getBaseType(), qual_begin(), getNumProtocols()); > + Profile(ID, getBaseType(), getTypeArgs(), > + llvm::makeArrayRef(qual_begin(), getNumProtocols())); > } > > namespace { > @@ -2495,6 +2537,39 @@ Optional<NullabilityKind> AttributedType > return None; > } > > +bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const { > + const ObjCObjectPointerType *objcPtr = getAs<ObjCObjectPointerType>(); > + if (!objcPtr) > + return false; > + > + if (objcPtr->isObjCIdType()) { > + // id is always okay. > + return true; > + } > + > + // Blocks are NSObjects. > + if (ObjCInterfaceDecl *iface = objcPtr->getInterfaceDecl()) { > + if (iface->getIdentifier() != ctx.getNSObjectName()) > + return false; > + > + // Continue to check qualifiers, below. > + } else if (objcPtr->isObjCQualifiedIdType()) { > + // Continue to check qualifiers, below. > + } else { > + return false; > + } > + > + // Check protocol qualifiers. > + for (ObjCProtocolDecl *proto : objcPtr->quals()) { > + // Blocks conform to NSObject and NSCopying. > + if (proto->getIdentifier() != ctx.getNSObjectName() && > + proto->getIdentifier() != ctx.getNSCopyingName()) > + return false; > + } > + > + return true; > +} > + > Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const { > if (isObjCARCImplicitlyUnretainedType()) > return Qualifiers::OCL_ExplicitNone; > > Modified: cfe/trunk/lib/AST/TypeLoc.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeLoc.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/TypeLoc.cpp (original) > +++ cfe/trunk/lib/AST/TypeLoc.cpp Mon Jul 6 22:57:35 2015 > @@ -312,6 +312,22 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLo > return TL; > } > > +void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, > + SourceLocation Loc) { > + setHasBaseTypeAsWritten(true); > + setTypeArgsLAngleLoc(Loc); > + setTypeArgsRAngleLoc(Loc); > + for (unsigned i = 0, e = getNumTypeArgs(); i != e; ++i) { > + setTypeArgTInfo(i, > + Context.getTrivialTypeSourceInfo( > + getTypePtr()->getTypeArgsAsWritten()[i], Loc)); > + } > + setProtocolLAngleLoc(Loc); > + setProtocolRAngleLoc(Loc); > + for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) > + setProtocolLoc(i, Loc); > +} > + > void TypeOfTypeLoc::initializeLocal(ASTContext &Context, > SourceLocation Loc) { > TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> > > Modified: cfe/trunk/lib/AST/TypePrinter.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/TypePrinter.cpp (original) > +++ cfe/trunk/lib/AST/TypePrinter.cpp Mon Jul 6 22:57:35 2015 > @@ -1310,59 +1310,56 @@ void TypePrinter::printObjCInterfaceAfte > > void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T, > raw_ostream &OS) { > - if (T->qual_empty()) > + if (T->qual_empty() && T->isUnspecializedAsWritten()) > return printBefore(T->getBaseType(), OS); > > print(T->getBaseType(), OS, StringRef()); > - OS << '<'; > - bool isFirst = true; > - for (const auto *I : T->quals()) { > - if (isFirst) > - isFirst = false; > - else > - OS << ','; > - OS << I->getName(); > + > + if (T->isSpecializedAsWritten()) { > + bool isFirst = true; > + OS << '<'; > + for (auto typeArg : T->getTypeArgsAsWritten()) { > + if (isFirst) > + isFirst = false; > + else > + OS << ","; > + > + print(typeArg, OS, StringRef()); > + } > + OS << '>'; > + } > + > + if (!T->qual_empty()) { > + bool isFirst = true; > + OS << '<'; > + for (const auto *I : T->quals()) { > + if (isFirst) > + isFirst = false; > + else > + OS << ','; > + OS << I->getName(); > + } > + OS << '>'; > } > - OS << '>'; > + > spaceBeforePlaceHolder(OS); > } > void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T, > raw_ostream &OS) { > - if (T->qual_empty()) > + if (T->qual_empty() && T->isUnspecializedAsWritten()) > return printAfter(T->getBaseType(), OS); > } > > void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType > *T, > raw_ostream &OS) { > - T->getPointeeType().getLocalQualifiers().print(OS, Policy, > - > /*appendSpaceIfNonEmpty=*/true); > + printBefore(T->getPointeeType(), OS); > > - assert(!T->isObjCSelType()); > - > - if (T->isObjCIdType() || T->isObjCQualifiedIdType()) > - OS << "id"; > - else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) > - OS << "Class"; > - else > - OS << T->getInterfaceDecl()->getName(); > - > - if (!T->qual_empty()) { > - OS << '<'; > - for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), > - E = T->qual_end(); > - I != E; ++I) { > - OS << (*I)->getName(); > - if (I+1 != E) > - OS << ','; > - } > - OS << '>'; > - } > - > + // If we need to print the pointer, print it now. > if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() && > !T->isObjCClassType() && !T->isObjCQualifiedClassType()) { > - OS << " *"; // Don't forget the implicit pointer. > - } else { > - spaceBeforePlaceHolder(OS); > + if (HasEmptyPlaceHolder) > + OS << ' '; > + OS << '*'; > } > } > void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType > *T, > > Modified: cfe/trunk/lib/Parse/ParseDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) > +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul 6 22:57:35 2015 > @@ -2886,11 +2886,26 @@ void Parser::ParseDeclarationSpecifiers( > DS.SetRangeEnd(Tok.getAnnotationEndLoc()); > ConsumeToken(); // The typename > > - // Objective-C supports syntax of the form 'id<proto1,proto2>' where > 'id' > - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an > - // Objective-C interface. > - if (Tok.is(tok::less) && getLangOpts().ObjC1) > - ParseObjCProtocolQualifiers(DS); > + // Objective-C supports type arguments and protocol references > + // following an Objective-C object pointer type. Handle either > + // one of them. > + if (Tok.is(tok::less) && getLangOpts().ObjC1) { > + ParseObjCTypeArgsOrProtocolQualifiers( > + DS, /*warnOnIncompleteProtocols=*/false); > + > + // An Objective-C object pointer followed by type arguments > + // can then be followed again by a set of protocol references, e.g., > + // \c NSArray<NSView><NSTextDelegate> > + if (Tok.is(tok::less)) { > + if (DS.getProtocolQualifiers()) { > + Diag(Tok, diag::err_objc_type_args_after_protocols) > + << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd()); > + SkipUntil(tok::greater, tok::greatergreater); > + } else { > + ParseObjCProtocolQualifiers(DS); > + } > + } > + } > > continue; > } > @@ -2997,11 +3012,26 @@ void Parser::ParseDeclarationSpecifiers( > DS.SetRangeEnd(Tok.getLocation()); > ConsumeToken(); // The identifier > > - // Objective-C supports syntax of the form 'id<proto1,proto2>' where > 'id' > - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an > - // Objective-C interface. > - if (Tok.is(tok::less) && getLangOpts().ObjC1) > - ParseObjCProtocolQualifiers(DS); > + // Objective-C supports type arguments and protocol references > + // following an Objective-C object pointer type. Handle either > + // one of them. > + if (Tok.is(tok::less) && getLangOpts().ObjC1) { > + ParseObjCTypeArgsOrProtocolQualifiers( > + DS, /*warnOnIncompleteProtocols=*/false); > + > + // An Objective-C object pointer followed by type arguments > + // can then be followed again by a set of protocol references, e.g., > + // \c NSArray<NSView><NSTextDelegate> > + if (Tok.is(tok::less)) { > + if (DS.getProtocolQualifiers()) { > + Diag(Tok, diag::err_objc_type_args_after_protocols) > + << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd()); > + SkipUntil(tok::greater, tok::greatergreater); > + } else { > + ParseObjCProtocolQualifiers(DS); > + } > + } > + } > > // Need to support trailing type qualifiers (e.g. "id<p> const"). > // If a type specifier follows, it will be diagnosed elsewhere. > > Modified: cfe/trunk/lib/Parse/ParseObjc.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Parse/ParseObjc.cpp (original) > +++ cfe/trunk/lib/Parse/ParseObjc.cpp Mon Jul 6 22:57:35 2015 > @@ -179,7 +179,7 @@ void Parser::CheckNestedObjCContexts(Sou > /// @end > /// > /// objc-superclass: > -/// ':' identifier > +/// ':' identifier objc-type-arguments[opt] > /// > /// objc-class-interface-attributes: > /// __attribute__((visibility("default"))) > @@ -293,6 +293,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclar > // Parse a class interface. > IdentifierInfo *superClassId = nullptr; > SourceLocation superClassLoc; > + DeclSpec superClassDS(AttrFactory); > > if (Tok.is(tok::colon)) { // a super class is specified. > ConsumeToken(); > @@ -311,18 +312,12 @@ Decl *Parser::ParseObjCAtInterfaceDeclar > } > superClassId = Tok.getIdentifierInfo(); > superClassLoc = ConsumeToken(); > - } else if (typeParameterList) { > - // An objc-type-parameter-list is ambiguous with an objc-protocol-refs > - // in an @interface without a specified superclass, so such classes > - // are ill-formed. We have determined that we have an > - // objc-type-parameter-list but no superclass, so complain and record > - // as if we inherited from NSObject. > - SourceLocation insertLoc = PP.getLocForEndOfToken(PrevTokLocation); > - Diag(insertLoc, diag::err_objc_parameterized_class_without_base) > - << nameId > - << FixItHint::CreateInsertion(insertLoc, " : NSObject"); > - superClassId = PP.getIdentifierInfo("NSObject"); > - superClassLoc = Tok.getLocation(); > + > + // Type arguments for the superclass or protocol conformances. > + if (Tok.is(tok::less)) { > + ParseObjCTypeArgsOrProtocolQualifiers(superClassDS, > + > /*warnOnIncompleteProtocols=*/true); > + } > } > > // Next, we need to check for any protocol references. > @@ -338,6 +333,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclar > /*ForObjCContainer=*/true, > &ProtocolIdents[0], > ProtocolIdents.size(), > ProtocolRefs); > + } else if (auto protocols = superClassDS.getProtocolQualifiers()) { > + // We already parsed the protocols named when we thought we had a > + // type argument list (for a specialized superclass). Treat them > + // as actual protocol references. > + unsigned numProtocols = superClassDS.getNumProtocolQualifiers(); > + ProtocolRefs.append(protocols, protocols + numProtocols); > + ProtocolLocs.append(superClassDS.getProtocolLocs(), > + superClassDS.getProtocolLocs() + numProtocols); > + LAngleLoc = superClassDS.getProtocolLAngleLoc(); > + EndProtoLoc = superClassDS.getLocEnd(); > } else if (Tok.is(tok::less) && > ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, > true, > LAngleLoc, EndProtoLoc)) { > @@ -348,8 +353,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclar > Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, > superClassLoc); > > Decl *ClsType = > - Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, > typeParameterList, > - superClassId, superClassLoc, > + Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, > + typeParameterList, superClassId, > + superClassLoc, > + superClassDS.getObjCTypeArgs(), > + superClassDS.getObjCTypeArgsRange(), > ProtocolRefs.data(), > ProtocolRefs.size(), > ProtocolLocs.data(), > EndProtoLoc, attrs.getList()); > @@ -1554,8 +1562,7 @@ bool Parser::ParseObjCProtocolQualifiers > SmallVector<Decl *, 8> ProtocolDecl; > SmallVector<SourceLocation, 8> ProtocolLocs; > bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, > false, > - false, > - LAngleLoc, EndProtoLoc); > + false, LAngleLoc, EndProtoLoc); > DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), > ProtocolLocs.data(), LAngleLoc); > if (EndProtoLoc.isValid()) > @@ -1563,6 +1570,111 @@ bool Parser::ParseObjCProtocolQualifiers > return Result; > } > > +/// Parse Objective-C type arguments or protocol qualifiers. > +/// > +/// objc-type-arguments: > +/// '<' type-name (',' type-name)* '>' > +/// > +void Parser::ParseObjCTypeArgsOrProtocolQualifiers( > + DeclSpec &DS, > + bool warnOnIncompleteProtocols) { > + assert(Tok.is(tok::less) && "Not at the start of type args or protocols"); > + SourceLocation lAngleLoc = ConsumeToken(); > + > + // Whether all of the elements we've parsed thus far are single > + // identifiers, which might be types or might be protocols. > + bool allSingleIdentifiers = true; > + SmallVector<IdentifierInfo *, 4> identifiers; > + SmallVector<SourceLocation, 4> identifierLocs; > + > + // Parse a list of comma-separated identifiers, bailing out if we > + // see something different. > + do { > + // Parse a single identifier. > + if (Tok.is(tok::identifier) && > + (NextToken().is(tok::comma) || > + NextToken().is(tok::greater) || > + NextToken().is(tok::greatergreater))) { > + identifiers.push_back(Tok.getIdentifierInfo()); > + identifierLocs.push_back(ConsumeToken()); > + continue; > + } > + > + if (Tok.is(tok::code_completion)) { > + // FIXME: Also include types here. > + SmallVector<IdentifierLocPair, 4> identifierLocPairs; > + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { > + identifierLocPairs.push_back(IdentifierLocPair(identifiers[i], > + identifierLocs[i])); > + } > + > + Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(), > + identifierLocPairs.size()); > + cutOffParsing(); > + return; > + } > + > + allSingleIdentifiers = false; > + break; > + } while (TryConsumeToken(tok::comma)); > + > + // If we parsed an identifier list, semantic analysis sorts out > + // whether it refers to protocols or to type arguments. > + if (allSingleIdentifiers) { > + // Parse the closing '>'. > + SourceLocation rAngleLoc; > + (void)ParseGreaterThanInTemplateList(rAngleLoc, > /*ConsumeLastToken=*/true, > + /*ObjCGenericList=*/true); > + > + // Let Sema figure out what we parsed. > + Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(), > + DS, > + lAngleLoc, > + identifiers, > + identifierLocs, > + rAngleLoc, > + warnOnIncompleteProtocols); > + return; > + } > + > + // We syntactically matched a type argument, so commit to parsing > + // type arguments. > + SmallVector<ParsedType, 4> typeArgs; > + > + // Convert the identifiers into type arguments. > + bool invalid = false; > + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { > + ParsedType typeArg > + = Actions.getTypeName(*identifiers[i], identifierLocs[i], > getCurScope()); > + if (typeArg) { > + typeArgs.push_back(typeArg); > + } else { > + invalid = true; > + } > + } > + > + // Continue parsing type-names. > + do { > + TypeResult typeArg = ParseTypeName(); > + if (typeArg.isUsable()) { > + typeArgs.push_back(typeArg.get()); > + } else { > + invalid = true; > + } > + } while (TryConsumeToken(tok::comma)); > + > + // Parse the closing '>'. > + SourceLocation rAngleLoc; > + (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true, > + /*ObjCGenericList=*/true); > + > + if (invalid) > + return; > + > + // Update the DeclSpec appropriately. > + DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc); > +} > + > void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, > SourceLocation atLoc, > BalancedDelimiterTracker &T, > SmallVectorImpl<Decl *> &AllIvarDecls, > > Modified: cfe/trunk/lib/Parse/ParseTentative.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Parse/ParseTentative.cpp (original) > +++ cfe/trunk/lib/Parse/ParseTentative.cpp Mon Jul 6 22:57:35 2015 > @@ -1384,7 +1384,7 @@ Parser::isCXXDeclarationSpecifier(Parser > case_typename: > // In Objective-C, we might have a protocol-qualified type. > if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { > - // Tentatively parse the > + // Tentatively parse the protocol qualifiers. > TentativeParsingAction PA(*this); > ConsumeToken(); // The type token > > > Modified: cfe/trunk/lib/Sema/DeclSpec.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/DeclSpec.cpp (original) > +++ cfe/trunk/lib/Sema/DeclSpec.cpp Mon Jul 6 22:57:35 2015 > @@ -893,6 +893,7 @@ bool DeclSpec::SetConstexprSpec(SourceLo > return false; > } > > + > bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, > unsigned &DiagID) { > if (Concept_specified) { > @@ -905,6 +906,16 @@ bool DeclSpec::SetConceptSpec(SourceLoca > return false; > } > > +void DeclSpec::setObjCTypeArgs(SourceLocation lAngleLoc, > + ArrayRef<ParsedType> args, > + SourceLocation rAngleLoc) { > + ParsedType *argsCopy = new ParsedType[args.size()]; > + memcpy(argsCopy, args.data(), args.size() * sizeof(ParsedType)); > + ObjCTypeArgs = llvm::makeArrayRef(argsCopy, args.size()); > + ObjCTypeArgsLAngleLoc = lAngleLoc; > + ObjCTypeArgsRAngleLoc = rAngleLoc; > +} > + > void DeclSpec::setProtocolQualifiers(Decl * const *Protos, > unsigned NP, > SourceLocation *ProtoLocs, > > Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Jul 6 22:57:35 2015 > @@ -464,6 +464,142 @@ static void diagnoseUseOfProtocols(Sema > } > } > > +void Sema:: > +ActOnSuperClassOfClassInterface(Scope *S, > + SourceLocation AtInterfaceLoc, > + ObjCInterfaceDecl *IDecl, > + IdentifierInfo *ClassName, > + SourceLocation ClassLoc, > + IdentifierInfo *SuperName, > + SourceLocation SuperLoc, > + ArrayRef<ParsedType> SuperTypeArgs, > + SourceRange SuperTypeArgsRange) { > + // Check if a different kind of symbol declared in this scope. > + NamedDecl *PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, > + LookupOrdinaryName); > + > + if (!PrevDecl) { > + // Try to correct for a typo in the superclass name without correcting > + // to the class we're defining. > + if (TypoCorrection Corrected = CorrectTypo( > + DeclarationNameInfo(SuperName, SuperLoc), > + LookupOrdinaryName, TUScope, > + NULL, llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), > + CTK_ErrorRecovery)) { > + diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) > + << SuperName << ClassName); > + PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); > + } > + } > + > + if (declaresSameEntity(PrevDecl, IDecl)) { > + Diag(SuperLoc, diag::err_recursive_superclass) > + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); > + IDecl->setEndOfDefinitionLoc(ClassLoc); > + } else { > + ObjCInterfaceDecl *SuperClassDecl = > + dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); > + QualType SuperClassType; > + > + // Diagnose classes that inherit from deprecated classes. > + if (SuperClassDecl) { > + (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); > + SuperClassType = Context.getObjCInterfaceType(SuperClassDecl); > + } > + > + if (PrevDecl && SuperClassDecl == 0) { > + // The previous declaration was not a class decl. Check if we have a > + // typedef. If we do, get the underlying class type. > + if (const TypedefNameDecl *TDecl = > + dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { > + QualType T = TDecl->getUnderlyingType(); > + if (T->isObjCObjectType()) { > + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) > { > + SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); > + SuperClassType = Context.getTypeDeclType(TDecl); > + > + // This handles the following case: > + // @interface NewI @end > + // typedef NewI DeprI __attribute__((deprecated("blah"))) > + // @interface SI : DeprI /* warn here */ @end > + (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), > SuperLoc); > + } > + } > + } > + > + // This handles the following case: > + // > + // typedef int SuperClass; > + // @interface MyClass : SuperClass {} @end > + // > + if (!SuperClassDecl) { > + Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; > + Diag(PrevDecl->getLocation(), diag::note_previous_definition); > + } > + } > + > + if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { > + if (!SuperClassDecl) > + Diag(SuperLoc, diag::err_undef_superclass) > + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); > + else if (RequireCompleteType(SuperLoc, > + SuperClassType, > + diag::err_forward_superclass, > + SuperClassDecl->getDeclName(), > + ClassName, > + SourceRange(AtInterfaceLoc, ClassLoc))) { > + SuperClassDecl = 0; > + SuperClassType = QualType(); > + } > + } > + > + if (SuperClassType.isNull()) { > + assert(!SuperClassDecl && "Failed to set SuperClassType?"); > + return; > + } > + > + // Handle type arguments on the superclass. > + TypeSourceInfo *SuperClassTInfo = nullptr; > + if (!SuperTypeArgs.empty()) { > + // Form declaration specifiers naming this superclass type with > + // type arguments. > + AttributeFactory attrFactory; > + DeclSpec DS(attrFactory); > + const char* prevSpec; // unused > + unsigned diagID; // unused > + TypeSourceInfo *parsedTSInfo > + = Context.getTrivialTypeSourceInfo(SuperClassType, SuperLoc); > + ParsedType parsedType = CreateParsedType(SuperClassType, parsedTSInfo); > + > + DS.SetTypeSpecType(DeclSpec::TST_typename, SuperLoc, prevSpec, diagID, > + parsedType, Context.getPrintingPolicy()); > + DS.SetRangeStart(SuperLoc); > + DS.SetRangeEnd(SuperLoc); > + DS.setObjCTypeArgs(SuperTypeArgsRange.getBegin(), > + SuperTypeArgs, > + SuperTypeArgsRange.getEnd()); > + > + // Form the declarator. > + Declarator D(DS, Declarator::TypeNameContext); > + > + TypeResult fullSuperClassType = ActOnTypeName(S, D); > + if (!fullSuperClassType.isUsable()) > + return; > + > + SuperClassType = GetTypeFromParser(fullSuperClassType.get(), > + &SuperClassTInfo); > + } > + > + if (!SuperClassTInfo) { > + SuperClassTInfo = Context.getTrivialTypeSourceInfo(SuperClassType, > + SuperLoc); > + } > + > + IDecl->setSuperClass(SuperClassTInfo); > + IDecl->setEndOfDefinitionLoc(SuperClassTInfo->getTypeLoc().getLocEnd()); > + } > +} > + > DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName, > SourceLocation paramLoc, > SourceLocation colonLoc, > @@ -499,7 +635,7 @@ DeclResult Sema::actOnObjCTypeParam(Scop > // Form the new type source information. > typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound); > } else { > - // Not a > + // Not a valid type bound. > Diag(typeBoundInfo->getTypeLoc().getBeginLoc(), > diag::err_objc_type_param_bound_nonobject) > << typeBound << paramName; > @@ -669,10 +805,12 @@ static bool checkTypeParamListConsistenc > } > > Decl *Sema:: > -ActOnStartClassInterface(SourceLocation AtInterfaceLoc, > +ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, > IdentifierInfo *ClassName, SourceLocation ClassLoc, > ObjCTypeParamList *typeParamList, > IdentifierInfo *SuperName, SourceLocation SuperLoc, > + ArrayRef<ParsedType> SuperTypeArgs, > + SourceRange SuperTypeArgsRange, > Decl * const *ProtoRefs, unsigned NumProtoRefs, > const SourceLocation *ProtoLocs, > SourceLocation EndProtoLoc, AttributeList > *AttrList) { > @@ -767,84 +905,13 @@ ActOnStartClassInterface(SourceLocation > IDecl->startDefinition(); > > if (SuperName) { > - // Check if a different kind of symbol declared in this scope. > - PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, > - LookupOrdinaryName); > - > - if (!PrevDecl) { > - // Try to correct for a typo in the superclass name without correcting > - // to the class we're defining. > - if (TypoCorrection Corrected = > - CorrectTypo(DeclarationNameInfo(SuperName, SuperLoc), > - LookupOrdinaryName, TUScope, nullptr, > - > llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), > - CTK_ErrorRecovery)) { > - diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) > - << SuperName << ClassName); > - PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); > - } > - } > - > - if (declaresSameEntity(PrevDecl, IDecl)) { > - Diag(SuperLoc, diag::err_recursive_superclass) > - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); > - IDecl->setEndOfDefinitionLoc(ClassLoc); > - } else { > - ObjCInterfaceDecl *SuperClassDecl = > - > dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); > - > - // Diagnose availability in the context of the @interface. > - ContextRAII SavedContext(*this, IDecl); > - // Diagnose classes that inherit from deprecated classes. > - if (SuperClassDecl) > - (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); > - > - if (PrevDecl && !SuperClassDecl) { > - // The previous declaration was not a class decl. Check if we have a > - // typedef. If we do, get the underlying class type. > - if (const TypedefNameDecl *TDecl = > - dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { > - QualType T = TDecl->getUnderlyingType(); > - if (T->isObjCObjectType()) { > - if (NamedDecl *IDecl = > T->getAs<ObjCObjectType>()->getInterface()) { > - SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); > - // This handles the following case: > - // @interface NewI @end > - // typedef NewI DeprI __attribute__((deprecated("blah"))) > - // @interface SI : DeprI /* warn here */ @end > - (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), > SuperLoc); > - } > - } > - } > - > - // This handles the following case: > - // > - // typedef int SuperClass; > - // @interface MyClass : SuperClass {} @end > - // > - if (!SuperClassDecl) { > - Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; > - Diag(PrevDecl->getLocation(), diag::note_previous_definition); > - } > - } > + // Diagnose availability in the context of the @interface. > + ContextRAII SavedContext(*this, IDecl); > > - if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { > - if (!SuperClassDecl) > - Diag(SuperLoc, diag::err_undef_superclass) > - << SuperName << ClassName << SourceRange(AtInterfaceLoc, > ClassLoc); > - else if (RequireCompleteType(SuperLoc, > - > Context.getObjCInterfaceType(SuperClassDecl), > - diag::err_forward_superclass, > - SuperClassDecl->getDeclName(), > - ClassName, > - SourceRange(AtInterfaceLoc, ClassLoc))) > { > - SuperClassDecl = nullptr; > - } > - } > - IDecl->setSuperClass(SuperClassDecl); > - IDecl->setSuperClassLoc(SuperLoc); > - IDecl->setEndOfDefinitionLoc(SuperLoc); > - } > + ActOnSuperClassOfClassInterface(S, AtInterfaceLoc, IDecl, > + ClassName, ClassLoc, > + SuperName, SuperLoc, SuperTypeArgs, > + SuperTypeArgsRange); > } else { // we have a root class. > IDecl->setEndOfDefinitionLoc(ClassLoc); > } > @@ -1091,6 +1158,325 @@ Sema::FindProtocolDeclaration(bool WarnO > } > } > > +// Callback to only accept typo corrections that are either > +// Objective-C protocols or valid Objective-C type arguments. > +class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback > { > + ASTContext &Context; > + Sema::LookupNameKind LookupKind; > + public: > + ObjCTypeArgOrProtocolValidatorCCC(ASTContext &context, > + Sema::LookupNameKind lookupKind) > + : Context(context), LookupKind(lookupKind) { } > + > + bool ValidateCandidate(const TypoCorrection &candidate) override { > + // If we're allowed to find protocols and we have a protocol, accept it. > + if (LookupKind != Sema::LookupOrdinaryName) { > + if (candidate.getCorrectionDeclAs<ObjCProtocolDecl>()) > + return true; > + } > + > + // If we're allowed to find type names and we have one, accept it. > + if (LookupKind != Sema::LookupObjCProtocolName) { > + // If we have a type declaration, we might accept this result. > + if (auto typeDecl = candidate.getCorrectionDeclAs<TypeDecl>()) { > + // If we found a tag declaration outside of C++, skip it. This > + // can happy because we look for any name when there is no > + // bias to protocol or type names. > + if (isa<RecordDecl>(typeDecl) && !Context.getLangOpts().CPlusPlus) > + return false; > + > + // Make sure the type is something we would accept as a type > + // argument. > + auto type = Context.getTypeDeclType(typeDecl); > + if (type->isObjCObjectPointerType() || > + type->isBlockPointerType() || > + type->isDependentType() || > + type->isObjCObjectType()) > + return true; > + > + return false; > + } > + > + // If we have an Objective-C class type, accept it; there will > + // be another fix to add the '*'. > + if (candidate.getCorrectionDeclAs<ObjCInterfaceDecl>()) > + return true; > + > + return false; > + } > + > + return false; > + } > +}; > + > +void Sema::actOnObjCTypeArgsOrProtocolQualifiers( > + Scope *S, > + DeclSpec &DS, > + SourceLocation lAngleLoc, > + ArrayRef<IdentifierInfo *> identifiers, > + ArrayRef<SourceLocation> identifierLocs, > + SourceLocation rAngleLoc, > + bool warnOnIncompleteProtocols) { > + // Local function that updates the declaration specifiers with > + // protocol information. > + SmallVector<ObjCProtocolDecl *, 4> protocols; > + unsigned numProtocolsResolved = 0; > + auto resolvedAsProtocols = [&] { > + assert(numProtocolsResolved == identifiers.size() && "Unresolved > protocols"); > + > + for (unsigned i = 0, n = protocols.size(); i != n; ++i) { > + ObjCProtocolDecl *&proto = protocols[i]; > + // For an objc container, delay protocol reference checking until > after we > + // can set the objc decl as the availability context, otherwise check > now. > + if (!warnOnIncompleteProtocols) { > + (void)DiagnoseUseOfDecl(proto, identifierLocs[i]); > + } > + > + // If this is a forward protocol declaration, get its definition. > + if (!proto->isThisDeclarationADefinition() && proto->getDefinition()) > + proto = proto->getDefinition(); > + > + // If this is a forward declaration and we are supposed to warn in this > + // case, do it. > + // FIXME: Recover nicely in the hidden case. > + ObjCProtocolDecl *forwardDecl = nullptr; > + if (warnOnIncompleteProtocols && > + NestedProtocolHasNoDefinition(proto, forwardDecl)) { > + Diag(identifierLocs[i], diag::warn_undef_protocolref) > + << proto->getDeclName(); > + Diag(forwardDecl->getLocation(), diag::note_protocol_decl_undefined) > + << forwardDecl; > + } > + } > + > + DS.setProtocolQualifiers((Decl * const *)(protocols.data()), > + protocols.size(), > + const_cast<SourceLocation > *>(identifierLocs.data()), > + lAngleLoc); > + if (rAngleLoc.isValid()) > + DS.SetRangeEnd(rAngleLoc); > + }; > + > + // Attempt to resolve all of the identifiers as protocols. > + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { > + ObjCProtocolDecl *proto = LookupProtocol(identifiers[i], > identifierLocs[i]); > + protocols.push_back(proto); > + if (proto) > + ++numProtocolsResolved; > + } > + > + // If all of the names were protocols, these were protocol qualifiers. > + if (numProtocolsResolved == identifiers.size()) > + return resolvedAsProtocols(); > + > + // Attempt to resolve all of the identifiers as type names or > + // Objective-C class names. The latter is technically ill-formed, > + // but is probably something like \c NSArray<NSView *> missing the > + // \c*. > + typedef llvm::PointerUnion<TypeDecl *, ObjCInterfaceDecl *> > TypeOrClassDecl; > + SmallVector<TypeOrClassDecl, 4> typeDecls; > + unsigned numTypeDeclsResolved = 0; > + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { > + NamedDecl *decl = LookupSingleName(S, identifiers[i], identifierLocs[i], > + LookupOrdinaryName); > + if (!decl) { > + typeDecls.push_back(TypeOrClassDecl()); > + continue; > + } > + > + if (auto typeDecl = dyn_cast<TypeDecl>(decl)) { > + typeDecls.push_back(typeDecl); > + ++numTypeDeclsResolved; > + continue; > + } > + > + if (auto objcClass = dyn_cast<ObjCInterfaceDecl>(decl)) { > + typeDecls.push_back(objcClass); > + ++numTypeDeclsResolved; > + continue; > + } > + > + typeDecls.push_back(TypeOrClassDecl()); > + } > + > + AttributeFactory attrFactory; > + > + // Local function that forms a reference to the given type or > + // Objective-C class declaration. > + auto resolveTypeReference = [&](TypeOrClassDecl typeDecl, SourceLocation > loc) > + -> TypeResult { > + // Form declaration specifiers. They simply refer to the type. > + DeclSpec DS(attrFactory); > + const char* prevSpec; // unused > + unsigned diagID; // unused > + QualType type; > + if (auto *actualTypeDecl = typeDecl.dyn_cast<TypeDecl *>()) > + type = Context.getTypeDeclType(actualTypeDecl); > + else > + type = Context.getObjCInterfaceType(typeDecl.get<ObjCInterfaceDecl > *>()); > + TypeSourceInfo *parsedTSInfo = Context.getTrivialTypeSourceInfo(type, > loc); > + ParsedType parsedType = CreateParsedType(type, parsedTSInfo); > + DS.SetTypeSpecType(DeclSpec::TST_typename, loc, prevSpec, diagID, > + parsedType, Context.getPrintingPolicy()); > + // Use the identifier location for the type source range. > + DS.SetRangeStart(loc); > + DS.SetRangeEnd(loc); > + > + // Form the declarator. > + Declarator D(DS, Declarator::TypeNameContext); > + > + // If we have a typedef of an Objective-C class type that is missing a > '*', > + // add the '*'. > + if (type->getAs<ObjCInterfaceType>()) { > + SourceLocation starLoc = PP.getLocForEndOfToken(loc); > + ParsedAttributes parsedAttrs(attrFactory); > + D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc, > + SourceLocation(), > + SourceLocation(), > + SourceLocation(), > + SourceLocation()), > + parsedAttrs, > + starLoc); > + > + // Diagnose the missing '*'. > + Diag(loc, diag::err_objc_type_arg_missing_star) > + << type > + << FixItHint::CreateInsertion(starLoc, " *"); > + } > + > + // Convert this to a type. > + return ActOnTypeName(S, D); > + }; > + > + // Local function that updates the declaration specifiers with > + // type argument information. > + auto resolvedAsTypeDecls = [&] { > + assert(numTypeDeclsResolved == identifiers.size() && "Unresolved type > decl"); > + // Map type declarations to type arguments. > + SmallVector<ParsedType, 4> typeArgs; > + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { > + // Map type reference to a type. > + TypeResult type = resolveTypeReference(typeDecls[i], > identifierLocs[i]); > + if (!type.isUsable()) > + return; > + > + typeArgs.push_back(type.get()); > + } > + > + // Record the Objective-C type arguments. > + DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc); > + }; > + > + // If all of the identifiers can be resolved as type names or > + // Objective-C class names, we have type arguments. > + if (numTypeDeclsResolved == identifiers.size()) > + return resolvedAsTypeDecls(); > + > + // Error recovery: some names weren't found, or we have a mix of > + // type and protocol names. Go resolve all of the unresolved names > + // and complain if we can't find a consistent answer. > + LookupNameKind lookupKind = LookupAnyName; > + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { > + // If we already have a protocol or type. Check whether it is the > + // right thing. > + if (protocols[i] || typeDecls[i]) { > + // If we haven't figured out whether we want types or protocols > + // yet, try to figure it out from this name. > + if (lookupKind == LookupAnyName) { > + // If this name refers to both a protocol and a type (e.g., \c > + // NSObject), don't conclude anything yet. > + if (protocols[i] && typeDecls[i]) > + continue; > + > + // Otherwise, let this name decide whether we'll be correcting > + // toward types or protocols. > + lookupKind = protocols[i] ? LookupObjCProtocolName > + : LookupOrdinaryName; > + continue; > + } > + > + // If we want protocols and we have a protocol, there's nothing > + // more to do. > + if (lookupKind == LookupObjCProtocolName && protocols[i]) > + continue; > + > + // If we want types and we have a type declaration, there's > + // nothing more to do. > + if (lookupKind == LookupOrdinaryName && typeDecls[i]) > + continue; > + > + // We have a conflict: some names refer to protocols and others > + // refer to types. > + Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols) > + << (protocols[i] != nullptr) > + << identifiers[i] > + << identifiers[0] > + << SourceRange(identifierLocs[0]); > + > + return; > + } > + > + // Perform typo correction on the name. > + TypoCorrection corrected = CorrectTypo( > + DeclarationNameInfo(identifiers[i], identifierLocs[i]), lookupKind, > S, > + nullptr, > + llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(Context, > + lookupKind), > + CTK_ErrorRecovery); > + if (corrected) { > + // Did we find a protocol? > + if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) { > + diagnoseTypo(corrected, > + PDiag(diag::err_undeclared_protocol_suggest) > + << identifiers[i]); > + lookupKind = LookupObjCProtocolName; > + protocols[i] = proto; > + ++numProtocolsResolved; > + continue; > + } > + > + // Did we find a type? > + if (auto typeDecl = corrected.getCorrectionDeclAs<TypeDecl>()) { > + diagnoseTypo(corrected, > + PDiag(diag::err_unknown_typename_suggest) > + << identifiers[i]); > + lookupKind = LookupOrdinaryName; > + typeDecls[i] = typeDecl; > + ++numTypeDeclsResolved; > + continue; > + } > + > + // Did we find an Objective-C class? > + if (auto objcClass = > corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { > + diagnoseTypo(corrected, > + PDiag(diag::err_unknown_type_or_class_name_suggest) > + << identifiers[i] << true); > + lookupKind = LookupOrdinaryName; > + typeDecls[i] = objcClass; > + ++numTypeDeclsResolved; > + continue; > + } > + } > + > + // We couldn't find anything. > + Diag(identifierLocs[i], > + (lookupKind == LookupAnyName ? diag::err_objc_type_arg_missing > + : lookupKind == LookupObjCProtocolName ? > diag::err_undeclared_protocol > + : diag::err_unknown_typename)) > + << identifiers[i]; > + return; > + } > + > + // If all of the names were (corrected to) protocols, these were > + // protocol qualifiers. > + if (numProtocolsResolved == identifiers.size()) > + return resolvedAsProtocols(); > + > + // Otherwise, all of the names were (corrected to) types. > + assert(numTypeDeclsResolved == identifiers.size() && "Not all types?"); > + return resolvedAsTypeDecls(); > +} > + > /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of > /// a class method in its extension. > /// > @@ -1374,8 +1760,9 @@ Decl *Sema::ActOnStartClassImplementatio > true); > IDecl->startDefinition(); > if (SDecl) { > - IDecl->setSuperClass(SDecl); > - IDecl->setSuperClassLoc(SuperClassLoc); > + IDecl->setSuperClass(Context.getTrivialTypeSourceInfo( > + Context.getObjCInterfaceType(SDecl), > + SuperClassLoc)); > IDecl->setEndOfDefinitionLoc(SuperClassLoc); > } else { > IDecl->setEndOfDefinitionLoc(ClassLoc); > > Modified: cfe/trunk/lib/Sema/SemaExpr.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jul 6 22:57:35 2015 > @@ -5826,36 +5826,6 @@ static QualType checkConditionalPointerC > return ResultTy; > } > > -/// \brief Returns true if QT is quelified-id and implements 'NSObject' > and/or > -/// 'NSCopying' protocols (and nothing else); or QT is an NSObject and > optionally > -/// implements 'NSObject' and/or NSCopying' protocols (and nothing else). > -static bool isObjCPtrBlockCompatible(Sema &S, ASTContext &C, QualType QT) { > - if (QT->isObjCIdType()) > - return true; > - > - const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>(); > - if (!OPT) > - return false; > - > - if (ObjCInterfaceDecl *ID = OPT->getInterfaceDecl()) > - if (ID->getIdentifier() != &C.Idents.get("NSObject")) > - return false; > - > - ObjCProtocolDecl* PNSCopying = > - S.LookupProtocol(&C.Idents.get("NSCopying"), SourceLocation()); > - ObjCProtocolDecl* PNSObject = > - S.LookupProtocol(&C.Idents.get("NSObject"), SourceLocation()); > - > - for (auto *Proto : OPT->quals()) { > - if ((PNSCopying && declaresSameEntity(Proto, PNSCopying)) || > - (PNSObject && declaresSameEntity(Proto, PNSObject))) > - ; > - else > - return false; > - } > - return true; > -} > - > /// \brief Return the resulting type when the operands are both block > pointers. > static QualType checkConditionalBlockPointerCompatibility(Sema &S, > ExprResult &LHS, > @@ -7008,8 +6978,8 @@ Sema::CheckAssignmentConstraints(QualTyp > } > > // Only under strict condition T^ is compatible with an Objective-C > pointer. > - if (RHSType->isBlockPointerType() && > - isObjCPtrBlockCompatible(*this, Context, LHSType)) { > + if (RHSType->isBlockPointerType() && > + LHSType->isBlockCompatibleObjCPointerType(Context)) { > maybeExtendBlockObject(*this, RHS); > Kind = CK_BlockPointerToObjCPointerCast; > return Compatible; > > Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Jul 6 22:57:35 2015 > @@ -959,8 +959,10 @@ ExprResult Sema::BuildObjCDictionaryLite > LookupProtocol(&Context.Idents.get("NSCopying"), > SR.getBegin())) { > ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; > QIDNSCopying = > - Context.getObjCObjectType(Context.ObjCBuiltinIdTy, > - (ObjCProtocolDecl**) PQ,1); > + Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, > + llvm::makeArrayRef( > + (ObjCProtocolDecl**) PQ, > + 1)); > QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); > } > } > > Modified: cfe/trunk/lib/Sema/SemaType.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaType.cpp (original) > +++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jul 6 22:57:35 2015 > @@ -738,6 +738,160 @@ static void diagnoseAndRemoveTypeQualifi > } > } > > +/// Apply Objective-C type arguments to the given type. > +static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, > + ArrayRef<ParsedType> typeArgs, > + SourceRange typeArgsRange) { > + // We can only apply type arguments to an Objective-C class type. > + const auto *objcObjectType = type->getAs<ObjCObjectType>(); > + if (!objcObjectType || !objcObjectType->getInterface()) { > + S.Diag(loc, diag::err_objc_type_args_non_class) > + << type > + << typeArgsRange; > + return type; > + } > + > + // The class type must be parameterized. > + ObjCInterfaceDecl *objcClass = objcObjectType->getInterface(); > + ObjCTypeParamList *typeParams = objcClass->getTypeParamList(); > + if (!typeParams) { > + S.Diag(loc, diag::err_objc_type_args_non_parameterized_class) > + << objcClass->getDeclName() > + << FixItHint::CreateRemoval(typeArgsRange); > + return type; > + } > + > + // The type must not already be specialized. > + if (objcObjectType->isSpecialized()) { > + S.Diag(loc, diag::err_objc_type_args_specialized_class) > + << type > + << FixItHint::CreateRemoval(typeArgsRange); > + return type; > + } > + > + // Make sure that we have the right number of type arguments. > + if (typeArgs.size() != typeParams->size()) { > + S.Diag(loc, diag::err_objc_type_args_wrong_arity) > + << (typeArgs.size() < typeParams->size()) > + << objcClass->getDeclName() > + << (unsigned)typeArgs.size() > + << (unsigned)typeParams->size(); > + S.Diag(objcClass->getLocation(), diag::note_previous_decl) > + << objcClass; > + return type; > + } > + > + // Check the type arguments. > + SmallVector<QualType, 4> finalTypeArgs; > + for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) { > + TypeSourceInfo *typeArgInfo = nullptr; > + QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo); > + finalTypeArgs.push_back(typeArg); > + > + // Objective-C object pointer types must be substitutable for the bounds. > + if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) { > + // Retrieve the bound. > + ObjCTypeParamDecl *typeParam = typeParams->begin()[i]; > + QualType bound = typeParam->getUnderlyingType(); > + const auto *boundObjC = bound->getAs<ObjCObjectPointerType>(); > + > + // Determine whether the type argument is substitutable for the bound. > + if (typeArgObjC->isObjCIdType()) { > + // When the type argument is 'id', the only acceptable type > + // parameter bound is 'id'. > + if (boundObjC->isObjCIdType()) > + continue; > + } else if (S.Context.canAssignObjCInterfaces(boundObjC, typeArgObjC)) { > + // Otherwise, we follow the assignability rules. > + continue; > + } > + > + // Diagnose the mismatch. > + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), > + diag::err_objc_type_arg_does_not_match_bound) > + << typeArg << bound << typeParam->getDeclName(); > + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) > + << typeParam->getDeclName(); > + > + return type; > + } > + > + // Block pointer types are permitted for unqualified 'id' bounds. > + if (typeArg->isBlockPointerType()) { > + // Retrieve the bound. > + ObjCTypeParamDecl *typeParam = typeParams->begin()[i]; > + QualType bound = typeParam->getUnderlyingType(); > + if (bound->isBlockCompatibleObjCPointerType(S.Context)) > + continue; > + > + // Diagnose the mismatch. > + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), > + diag::err_objc_type_arg_does_not_match_bound) > + << typeArg << bound << typeParam->getDeclName(); > + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) > + << typeParam->getDeclName(); > + > + return type; > + } > + > + // Dependent types will be checked at instantiation time. > + if (typeArg->isDependentType()) { > + continue; > + } > + > + // Diagnose non-id-compatible type arguments. > + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), > + diag::err_objc_type_arg_not_id_compatible) > + << typeArg > + << typeArgInfo->getTypeLoc().getSourceRange(); > + return type; > + } > + > + // Success. Form the specialized type. > + return S.Context.getObjCObjectType(type, finalTypeArgs, { }); > +} > + > +/// Apply Objective-C protocol qualifiers to the given type. > +static QualType applyObjCProtocolQualifiers( > + Sema &S, SourceLocation loc, SourceRange range, QualType > type, > + ArrayRef<ObjCProtocolDecl *> protocols, > + const SourceLocation *protocolLocs) { > + ASTContext &ctx = S.Context; > + if (const ObjCObjectType *objT = > dyn_cast<ObjCObjectType>(type.getTypePtr())){ > + // FIXME: Check for protocols to which the class type is already > + // known to conform. > + > + return ctx.getObjCObjectType(objT->getBaseType(), > + objT->getTypeArgsAsWritten(), > + protocols); > + } > + > + if (type->isObjCObjectType()) { > + // Silently overwrite any existing protocol qualifiers. > + // TODO: determine whether that's the right thing to do. > + > + // FIXME: Check for protocols to which the class type is already > + // known to conform. > + return ctx.getObjCObjectType(type, { }, protocols); > + } > + > + // id<protocol-list> > + if (type->isObjCIdType()) { > + type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols); > + return ctx.getObjCObjectPointerType(type); > + } > + > + // Class<protocol-list> > + if (type->isObjCClassType()) { > + type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols); > + return ctx.getObjCObjectPointerType(type); > + } > + > + S.Diag(loc, diag::err_invalid_protocol_qualifiers) > + << range; > + return type; > +} > + > /// \brief Convert the specified declspec to the appropriate type > /// object. > /// \param state Specifies the declarator containing the declaration > specifier > @@ -803,9 +957,10 @@ static QualType ConvertDeclSpecToType(Ty > case DeclSpec::TST_unspecified: > // "<proto1,proto2>" is an objc qualified ID with a missing id. > if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { > - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, > - (ObjCProtocolDecl*const*)PQ, > - DS.getNumProtocolQualifiers()); > + Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, > + llvm::makeArrayRef( > + (ObjCProtocolDecl*const*)PQ, > + DS.getNumProtocolQualifiers())); > Result = Context.getObjCObjectPointerType(Result); > break; > } > @@ -967,37 +1122,8 @@ static QualType ConvertDeclSpecToType(Ty > DS.getTypeSpecSign() == 0 && > "Can't handle qualifiers on typedef names yet!"); > Result = S.GetTypeFromParser(DS.getRepAsType()); > - if (Result.isNull()) > + if (Result.isNull()) { > declarator.setInvalidType(true); > - else if (DeclSpec::ProtocolQualifierListTy PQ > - = DS.getProtocolQualifiers()) { > - if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { > - // Silently drop any existing protocol qualifiers. > - // TODO: determine whether that's the right thing to do. > - if (ObjT->getNumProtocols()) > - Result = ObjT->getBaseType(); > - > - if (DS.getNumProtocolQualifiers()) > - Result = Context.getObjCObjectType(Result, > - (ObjCProtocolDecl*const*) PQ, > - DS.getNumProtocolQualifiers()); > - } else if (Result->isObjCIdType()) { > - // id<protocol-list> > - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, > - (ObjCProtocolDecl*const*) PQ, > - DS.getNumProtocolQualifiers()); > - Result = Context.getObjCObjectPointerType(Result); > - } else if (Result->isObjCClassType()) { > - // Class<protocol-list> > - Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, > - (ObjCProtocolDecl*const*) PQ, > - DS.getNumProtocolQualifiers()); > - Result = Context.getObjCObjectPointerType(Result); > - } else { > - S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) > - << DS.getSourceRange(); > - declarator.setInvalidType(true); > - } > } else if (S.getLangOpts().OpenCL) { > if (const AtomicType *AT = Result->getAs<AtomicType>()) { > const BuiltinType *BT = AT->getValueType()->getAs<BuiltinType>(); > @@ -1022,6 +1148,21 @@ static QualType ConvertDeclSpecToType(Ty > declarator.setInvalidType(true); > } > } > + } else { > + // Apply Objective-C type arguments. > + if (DS.hasObjCTypeArgs()) { > + Result = applyObjCTypeArgs(S, DeclLoc, Result, DS.getObjCTypeArgs(), > + DS.getObjCTypeArgsRange()); > + } > + > + // Apply Objective-C protocol qualifiers. > + if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) > { > + Result = applyObjCProtocolQualifiers( > + S, DeclLoc, DS.getSourceRange(), Result, > + llvm::makeArrayRef((ObjCProtocolDecl * const *)PQ, > + DS.getNumProtocolQualifiers()), > + DS.getProtocolLocs()); > + } > } > > // TypeQuals handled by caller. > @@ -4138,18 +4279,33 @@ namespace { > Visit(TL.getBaseLoc()); > } > > + // Type arguments. > + if (TL.getNumTypeArgs() > 0) { > + assert(TL.getNumTypeArgs() == DS.getObjCTypeArgs().size()); > + TL.setTypeArgsLAngleLoc(DS.getObjCTypeArgsLAngleLoc()); > + TL.setTypeArgsRAngleLoc(DS.getObjCTypeArgsRAngleLoc()); > + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) { > + TypeSourceInfo *typeArgInfo = nullptr; > + (void)Sema::GetTypeFromParser(DS.getObjCTypeArgs()[i], > &typeArgInfo); > + TL.setTypeArgTInfo(i, typeArgInfo); > + } > + } else { > + TL.setTypeArgsLAngleLoc(SourceLocation()); > + TL.setTypeArgsRAngleLoc(SourceLocation()); > + } > + > // Protocol qualifiers. > if (DS.getProtocolQualifiers()) { > assert(TL.getNumProtocols() > 0); > assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); > - TL.setLAngleLoc(DS.getProtocolLAngleLoc()); > - TL.setRAngleLoc(DS.getSourceRange().getEnd()); > + TL.setProtocolLAngleLoc(DS.getProtocolLAngleLoc()); > + TL.setProtocolRAngleLoc(DS.getSourceRange().getEnd()); > for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) > TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); > } else { > assert(TL.getNumProtocols() == 0); > - TL.setLAngleLoc(SourceLocation()); > - TL.setRAngleLoc(SourceLocation()); > + TL.setProtocolLAngleLoc(SourceLocation()); > + TL.setProtocolRAngleLoc(SourceLocation()); > } > } > void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { > > Modified: cfe/trunk/lib/Serialization/ASTReader.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Jul 6 22:57:35 2015 > @@ -5263,11 +5263,15 @@ QualType ASTReader::readTypeRecord(unsig > case TYPE_OBJC_OBJECT: { > unsigned Idx = 0; > QualType Base = readType(*Loc.F, Record, Idx); > + unsigned NumTypeArgs = Record[Idx++]; > + SmallVector<QualType, 4> TypeArgs; > + for (unsigned I = 0; I != NumTypeArgs; ++I) > + TypeArgs.push_back(readType(*Loc.F, Record, Idx)); > unsigned NumProtos = Record[Idx++]; > SmallVector<ObjCProtocolDecl*, 4> Protos; > for (unsigned I = 0; I != NumProtos; ++I) > Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); > - return Context.getObjCObjectType(Base, Protos.data(), NumProtos); > + return Context.getObjCObjectType(Base, TypeArgs, Protos); > } > > case TYPE_OBJC_OBJECT_POINTER: { > @@ -5646,8 +5650,12 @@ void TypeLocReader::VisitObjCInterfaceTy > } > void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { > TL.setHasBaseTypeAsWritten(Record[Idx++]); > - TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); > - TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); > + TL.setTypeArgsLAngleLoc(ReadSourceLocation(Record, Idx)); > + TL.setTypeArgsRAngleLoc(ReadSourceLocation(Record, Idx)); > + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) > + TL.setTypeArgTInfo(i, Reader.GetTypeSourceInfo(F, Record, Idx)); > + TL.setProtocolLAngleLoc(ReadSourceLocation(Record, Idx)); > + TL.setProtocolRAngleLoc(ReadSourceLocation(Record, Idx)); > for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) > TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx)); > } > > Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Jul 6 22:57:35 2015 > @@ -953,8 +953,7 @@ void ASTDeclReader::VisitObjCInterfaceDe > ObjCInterfaceDecl::DefinitionData &Data = ID->data(); > > // Read the superclass. > - Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); > - Data.SuperClassLoc = ReadSourceLocation(Record, Idx); > + Data.SuperClassTInfo = GetTypeSourceInfo(Record, Idx); > > Data.EndLoc = ReadSourceLocation(Record, Idx); > Data.HasDesignatedInitializers = Record[Idx++]; > > Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Jul 6 22:57:35 2015 > @@ -421,6 +421,9 @@ void ASTTypeWriter::VisitObjCInterfaceTy > > void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { > Writer.AddTypeRef(T->getBaseType(), Record); > + Record.push_back(T->getTypeArgs().size()); > + for (auto TypeArg : T->getTypeArgs()) > + Writer.AddTypeRef(TypeArg, Record); > Record.push_back(T->getNumProtocols()); > for (const auto *I : T->quals()) > Writer.AddDeclRef(I, Record); > @@ -648,8 +651,12 @@ void TypeLocWriter::VisitObjCInterfaceTy > } > void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { > Record.push_back(TL.hasBaseTypeAsWritten()); > - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); > - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); > + Writer.AddSourceLocation(TL.getTypeArgsLAngleLoc(), Record); > + Writer.AddSourceLocation(TL.getTypeArgsRAngleLoc(), Record); > + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) > + Writer.AddTypeSourceInfo(TL.getTypeArgTInfo(i), Record); > + Writer.AddSourceLocation(TL.getProtocolLAngleLoc(), Record); > + Writer.AddSourceLocation(TL.getProtocolRAngleLoc(), Record); > for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) > Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); > } > > Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) > +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Mon Jul 6 22:57:35 2015 > @@ -604,8 +604,7 @@ void ASTDeclWriter::VisitObjCInterfaceDe > // Write the DefinitionData > ObjCInterfaceDecl::DefinitionData &Data = D->data(); > > - Writer.AddDeclRef(D->getSuperClass(), Record); > - Writer.AddSourceLocation(D->getSuperClassLoc(), Record); > + Writer.AddTypeSourceInfo(D->getSuperClassTInfo(), Record); > Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record); > Record.push_back(Data.HasDesignatedInitializers); > > > Added: cfe/trunk/test/Index/annotate-parameterized-classes.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-parameterized-classes.m?rev=241542&view=auto > ============================================================================== > --- cfe/trunk/test/Index/annotate-parameterized-classes.m (added) > +++ cfe/trunk/test/Index/annotate-parameterized-classes.m Mon Jul 6 22:57:35 > 2015 > @@ -0,0 +1,42 @@ > +@protocol NSObject > +@end > + > +@interface NSObject > +@end > + > +@interface A<T : id, U : NSObject *> : NSObject > +@end > + > +@interface A<T : id, U : NSObject *> (Cat1) > +@end > + > +typedef A<id<NSObject>, NSObject *> ASpecialization1; > + > +@interface B<T : id, U : NSObject *> : A<T, U> > +@end > + > +// RUN: c-index-test -test-annotate-tokens=%s:7:1:9:1 %s -target > x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-INTERFACE-DECL %s > +// CHECK-INTERFACE-DECL: Identifier: "T" [7:14 - 7:15] > TemplateTypeParameter=T:7:14 > +// FIXME: Should be a type reference > +// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] > TemplateTypeParameter=T:7:14 > +// CHECK-INTERFACE-DECL: Identifier: "U" [7:22 - 7:23] > TemplateTypeParameter=U:7:22 > +// FIXME: Should be a class reference > +// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] > TemplateTypeParameter=U:7:22 > + > +// RUN: c-index-test -test-annotate-tokens=%s:10:1:12:1 %s -target > x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-CATEGORY-DECL %s > +// CHECK-CATEGORY-DECL: Identifier: "T" [10:14 - 10:15] > TemplateTypeParameter=T:10:14 > +// FIXME: Should be a type reference > +// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] > TemplateTypeParameter=T:10:14 > +// CHECK-CATEGORY-DECL: Identifier: "U" [10:22 - 10:23] > TemplateTypeParameter=U:10:22 > +// FIXME: Should be a class reference > +// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] > TemplateTypeParameter=U:10:22 > + > +// RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 %s -target > x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SPECIALIZATION %s > +// CHECK-SPECIALIZATION: Identifier: "id" [13:11 - 13:13] TypeRef=id:0:0 > +// CHECK-SPECIALIZATION: Identifier: "NSObject" [13:14 - 13:22] > ObjCProtocolRef=NSObject:1:11 > +// CHECK-SPECIALIZATION: Identifier: "NSObject" [13:25 - 13:33] > ObjCClassRef=NSObject:4:12 > + > +// RUN: c-index-test -test-annotate-tokens=%s:15:1:16:1 %s -target > x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SUPER %s > +// CHECK-SUPER: Identifier: "A" [15:40 - 15:41] ObjCSuperClassRef=A:7:12 > +// CHECK-SUPER: Identifier: "T" [15:42 - 15:43] TypeRef=T:15:14 > +// CHECK-SUPER: Identifier: "U" [15:45 - 15:46] TypeRef=U:15:22 > > Modified: cfe/trunk/test/Index/complete-method-decls.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-method-decls.m?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/test/Index/complete-method-decls.m (original) > +++ cfe/trunk/test/Index/complete-method-decls.m Mon Jul 6 22:57:35 2015 > @@ -208,8 +208,7 @@ typedef A *MyObjectRef; > > // RUN: c-index-test -code-completion-at=%s:85:2 %s | FileCheck > -check-prefix=CHECK-CLASSTY %s > // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text > Class<P1>}{RightParen )}{TypedText meth} > -// FIXME: It should be "MyObject <P1> *"" > -// CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text A<P1> > *}{RightParen )}{TypedText meth2} > +// CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text MyObject<P1> > *}{RightParen )}{TypedText meth2} > // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text > MyObjectRef}{RightParen )}{TypedText meth3} > > // RUN: c-index-test -code-completion-at=%s:93:2 %s | FileCheck > -check-prefix=CHECK-NULLABILITY %s > > Modified: cfe/trunk/test/PCH/objc_parameterized_classes.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_parameterized_classes.m?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/test/PCH/objc_parameterized_classes.m (original) > +++ cfe/trunk/test/PCH/objc_parameterized_classes.m Mon Jul 6 22:57:35 2015 > @@ -19,6 +19,8 @@ __attribute__((objc_root_class)) > @interface PC1<T, U : NSObject *> (Cat1) > @end > > +typedef PC1<id, NSObject *> PC1Specialization1; > + > #else > > @interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' > for type parameter 'T' conflicts with implicit bound 'id}} > @@ -27,4 +29,6 @@ __attribute__((objc_root_class)) > // expected-note@15{{type parameter 'U' declared here}} > @end > > +typedef PC1Specialization1<id, NSObject *> PC1Specialization2; // > expected-error{{type arguments cannot be applied to already-specialized class > type 'PC1Specialization1' (aka 'PC1<id,NSObject *>')}} > + > #endif > > Modified: cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm (original) > +++ cfe/trunk/test/Parser/objcxx11-protocol-in-template.mm Mon Jul 6 > 22:57:35 2015 > @@ -4,12 +4,7 @@ > template<class T> class vector {}; > @protocol P @end > > -#if __cplusplus >= 201103L > - // expected-no-diagnostics > -#else > - // expected-error@14{{a space is required between consecutive right angle > brackets}} > - // expected-error@15{{a space is required between consecutive right angle > brackets}} > -#endif > +// expected-no-diagnostics > > vector<id<P>> v; > vector<vector<id<P>>> v2; > > Modified: cfe/trunk/test/SemaObjC/interface-1.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/interface-1.m?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/test/SemaObjC/interface-1.m (original) > +++ cfe/trunk/test/SemaObjC/interface-1.m Mon Jul 6 22:57:35 2015 > @@ -3,7 +3,7 @@ > > @interface NSWhatever : > NSObject // expected-error {{cannot find interface declaration for > 'NSObject'}} > -<NSCopying> // expected-error {{cannot find protocol declaration for > 'NSCopying'}} > +<NSCopying> // expected-error {{no type or protocol named 'NSCopying'}} > @end > > > > Modified: cfe/trunk/test/SemaObjC/parameterized_classes.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes.m?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/test/SemaObjC/parameterized_classes.m (original) > +++ cfe/trunk/test/SemaObjC/parameterized_classes.m Mon Jul 6 22:57:35 2015 > @@ -1,13 +1,16 @@ > -// RUN: %clang_cc1 %s -verify > +// RUN: %clang_cc1 -fblocks %s -verify > > -@protocol NSObject > +@protocol NSObject // expected-note{{'NSObject' declared here}} > +@end > + > +@protocol NSCopying // expected-note{{'NSCopying' declared here}} > @end > > __attribute__((objc_root_class)) > @interface NSObject <NSObject> // expected-note{{'NSObject' defined here}} > @end > > -@interface NSString : NSObject > +@interface NSString : NSObject <NSCopying> > @end > > // -------------------------------------------------------------------------- > @@ -15,13 +18,14 @@ __attribute__((objc_root_class)) > // -------------------------------------------------------------------------- > > // Parse type parameters with a bound > -@interface PC1<T, U : NSObject*> : NSObject > +@interface PC1<T, U : NSObject*> : NSObject // expected-note{{'PC1' declared > here}} > // expected-note@-1{{type parameter 'T' declared here}} > // expected-note@-2{{type parameter 'U' declared here}} > +// expected-note@-3{{type parameter 'U' declared here}} > @end > > // Parse a type parameter with a bound that terminates in '>>'. > -@interface PC2<T : id<NSObject>> : NSObject // expected-error{{a space is > required between consecutive right angle brackets (use '> >')}} > +@interface PC2<T : id<NSObject>> : NSObject > @end > > // Parse multiple type parameters. > @@ -29,11 +33,11 @@ __attribute__((objc_root_class)) > @end > > // Parse multiple type parameters--grammatically ambiguous with protocol > refs. > -@interface PC4<T, U, V> : NSObject > +@interface PC4<T, U, V> : NSObject // expected-note 2{{'PC4' declared here}} > @end > > // Parse a type parameter list without a superclass. > -@interface PC5<T : id> // expected-error{{parameterized Objective-C class > 'PC5' must have a superclass}} > +@interface PC5<T : id> > @end > > // Parse a type parameter with name conflicts. > @@ -92,6 +96,7 @@ __attribute__((objc_root_class)) > > // Parameterized forward declaration a class that is not parameterized. > @class NSObject<T>; // expected-error{{forward declaration of > non-parameterized class 'NSObject' cannot have type parameters}} > +// expected-note@-1{{'NSObject' declared here}} > > // Parameterized forward declaration preceding the definition (that is > // not parameterized). > @@ -190,3 +195,131 @@ void test_PC20_unspecialized(PC20 *pc20) > ip = [pc20 extMethod: 0]; // expected-warning{{incompatible pointer types > assigning to 'int *' from 'X' (aka 'id')}} > [pc20 extMethod: ip]; // expected-warning{{incompatible pointer types > sending 'int *' to parameter of type 'Y' (aka 'NSObject *')}} > } > + > +// -------------------------------------------------------------------------- > +// Parsing type arguments. > +// -------------------------------------------------------------------------- > + > +typedef NSString * ObjCStringRef; // expected-note{{'ObjCStringRef' declared > here}} > + > +// Type arguments with a mix of identifiers and type-names. > +typedef PC4<id, NSObject *, NSString *> typeArgs1; > + > +// Type arguments with only identifiers. > +typedef PC4<id, id, id> typeArgs2; > + > +// Type arguments with only identifiers; one is ambiguous (resolved as > +// types). > +typedef PC4<NSObject, id, id> typeArgs3; // expected-error{{type argument > 'NSObject' must be a pointer (requires a '*')}} > + > +// Type arguments with only identifiers; one is ambiguous (resolved as > +// protocol qualifiers). > +typedef PC4<NSObject, NSCopying> protocolQuals1; > + > +// Type arguments and protocol qualifiers. > +typedef PC4<id, NSObject *, id><NSObject, NSCopying> > typeArgsAndProtocolQuals1; > + > +// Type arguments and protocol qualifiers in the wrong order. > +typedef PC4<NSObject, NSCopying><id, NSObject *, id> > typeArgsAndProtocolQuals2; // expected-error{{protocol qualifiers must > precede type arguments}} > + > +// Type arguments and protocol qualifiers (identifiers). > +typedef PC4<id, NSObject, id><NSObject, NSCopying> > typeArgsAndProtocolQuals3; // expected-error{{type argument 'NSObject' must > be a pointer (requires a '*')}} > + > +// Typo correction: protocol bias. > +typedef PC4<NSCopying, NSObjec> protocolQuals2; // expected-error{{cannot > find protocol declaration for 'NSObjec'; did you mean 'NSObject'?}} > + > +// Typo correction: type bias. > +typedef PC4<id, id, NSObjec> typeArgs4; // expected-error{{unknown class > name 'NSObjec'; did you mean 'NSObject'?}} > +// expected-error@-1{{type argument 'NSObject' must be a pointer (requires a > '*')}} > + > +// Typo correction: bias set by correction itself to a protocol. > +typedef PC4<NSObject, NSObject, NSCopyin> protocolQuals3; // > expected-error{{cannot find protocol declaration for 'NSCopyin'; did you mean > 'NSCopying'?}} > + > +// Typo correction: bias set by correction itself to a type. > +typedef PC4<NSObject, NSObject, ObjCStringref> typeArgs5; // > expected-error{{unknown type name 'ObjCStringref'; did you mean > 'ObjCStringRef'?}} > +// expected-error@-1{{type argument 'NSObject' must be a pointer (requires a > '*')}} > +// expected-error@-2{{type argument 'NSObject' must be a pointer (requires a > '*')}} > + > +// Type/protocol conflict. > +typedef PC4<NSCopying, ObjCStringRef> typeArgsProtocolQualsConflict1; // > expected-error{{angle brackets contain both a type ('ObjCStringRef') and a > protocol ('NSCopying')}} > + > +// Handling the '>>' in type argument lists. > +typedef PC4<id<NSCopying>, NSObject *, id<NSObject>> typeArgs6; > + > +// -------------------------------------------------------------------------- > +// Checking type arguments. > +// -------------------------------------------------------------------------- > + > +@interface PC15<T : id, U : NSObject *, V : id<NSCopying>> : NSObject > +// expected-note@-1{{type parameter 'V' declared here}} > +// expected-note@-2{{type parameter 'V' declared here}} > +// expected-note@-3{{type parameter 'U' declared here}} > +@end > + > +typedef PC4<NSString *> tooFewTypeArgs1; // expected-error{{too few type > arguments for class 'PC4' (have 1, expected 3)}} > + > +typedef PC4<NSString *, NSString *, NSString *, NSString *> > tooManyTypeArgs1; // expected-error{{too many type arguments for class 'PC4' > (have 4, expected 3)}} > + > +typedef PC15<int (^)(int, int), // block pointers as 'id' > + NSString *, // subclass > + NSString *> typeArgs7; // class that conforms to the protocol > + > +typedef PC15<NSObject *, NSObject *, id<NSCopying>> typeArgs8; > + > +typedef PC15<NSObject *, NSObject *, > + NSObject *> typeArgs8b; // expected-error{{type argument > 'NSObject *' does not satisy the bound ('id<NSCopying>') of type parameter > 'V'}} > + > +typedef PC15<id, > + id, // expected-error{{type argument 'id' does not satisy the > bound ('NSObject *') of type parameter 'U'}} > + id> typeArgs9; > + > +typedef PC15<id, NSObject *, > + id> typeArgs10; // expected-error{{type argument 'id' does not > satisy the bound ('id<NSCopying>') of type parameter 'V'}} > + > +typedef PC15<id, > + int (^)(int, int), // okay > + id<NSCopying, NSObject>> typeArgs11; > + > +typedef PC15<id, NSString *, int (^)(int, int)> typeArgs12; // okay > + > +typedef NSObject<id, id> typeArgs13; // expected-error{{type arguments > cannot be applied to non-parameterized class 'NSObject'}} > + > +typedef id<id, id> typeArgs14; // expected-error{{type arguments cannot be > applied to non-class type 'id'}} > + > +typedef PC1<NSObject *, NSString *> typeArgs15; > + > +typedef PC1<NSObject *, NSString *><NSCopying> typeArgsAndProtocolQuals4; > + > +typedef typeArgs15<NSCopying> typeArgsAndProtocolQuals5; > + > +typedef typeArgs15<NSObject *, NSString *> typeArgs16; // > expected-error{{type arguments cannot be applied to already-specialized class > type 'typeArgs15' (aka 'PC1<NSObject *,NSString *>')}} > + > +typedef typeArgs15<NSObject> typeArgsAndProtocolQuals6; > + > +void testSpecializedTypePrinting() { > + int *ip; > + > + ip = (typeArgs15*)0; // expected-warning{{'typeArgs15 *' (aka > 'PC1<NSObject *,NSString *> *')}} > + ip = (typeArgsAndProtocolQuals4*)0; // > expected-warning{{'typeArgsAndProtocolQuals4 *' (aka 'PC1<NSObject *,NSString > *><NSCopying> *')}} > + ip = (typeArgsAndProtocolQuals5*)0; // > expected-warning{{'typeArgsAndProtocolQuals5 *' (aka 'typeArgs15<NSCopying> > *')}} > + ip = (typeArgsAndProtocolQuals6)0; // expected-error{{used type > 'typeArgsAndProtocolQuals6' (aka 'typeArgs15<NSObject>')}} > + ip = (typeArgsAndProtocolQuals6*)0;// > expected-warning{{'typeArgsAndProtocolQuals6 *' (aka 'typeArgs15<NSObject> > *')}} > +} > + > +// -------------------------------------------------------------------------- > +// Specialized superclasses > +// -------------------------------------------------------------------------- > +@interface PC21<T : NSObject *> : PC1<T, T> > +@end > + > +@interface PC22<T : NSObject *> : PC1<T> // expected-error{{too few type > arguments for class 'PC1' (have 1, expected 2)}} > +@end > + > +@interface PC23<T : NSObject *> : PC1<T, U> // expected-error{{unknown type > name 'U'}} > +@end > + > +@interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka > 'id') does not satisy the bound ('NSObject *') of type parameter 'U'}} > +@end > + > +@interface NSFoo : PC1<NSObject *, NSObject *> // okay > +@end > > Added: cfe/trunk/test/SemaObjCXX/parameterized_classes.mm > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/parameterized_classes.mm?rev=241542&view=auto > ============================================================================== > --- cfe/trunk/test/SemaObjCXX/parameterized_classes.mm (added) > +++ cfe/trunk/test/SemaObjCXX/parameterized_classes.mm Mon Jul 6 22:57:35 > 2015 > @@ -0,0 +1,26 @@ > +// RUN: %clang_cc1 -std=c++11 %s -verify > + > +// expected-no-diagnostics > +@protocol NSObject > +@end > + > +@protocol NSCopying > +@end > + > +__attribute__((objc_root_class)) > +@interface NSObject <NSObject> > +@end > + > +@interface NSString : NSObject > +@end > + > +// -------------------------------------------------------------------------- > +// Parsing parameterized classes. > +// -------------------------------------------------------------------------- > +@interface PC1<T, U, V> : NSObject > +@end > + > +// -------------------------------------------------------------------------- > +// Parsing type arguments. > +// -------------------------------------------------------------------------- > +typedef PC1<::NSString *, NSString *, id<NSCopying>> typeArgs1; > > Modified: cfe/trunk/tools/libclang/CIndex.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/tools/libclang/CIndex.cpp (original) > +++ cfe/trunk/tools/libclang/CIndex.cpp Mon Jul 6 22:57:35 2015 > @@ -1021,6 +1021,9 @@ bool CursorVisitor::VisitObjCCategoryDec > TU))) > return true; > > + if (VisitObjCTypeParamList(ND->getTypeParamList())) > + return true; > + > ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin(); > for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(), > E = ND->protocol_end(); I != E; ++I, ++PL) > @@ -1080,12 +1083,37 @@ bool CursorVisitor::VisitObjCPropertyDec > return false; > } > > +bool CursorVisitor::VisitObjCTypeParamList(ObjCTypeParamList *typeParamList) > { > + if (!typeParamList) > + return false; > + > + for (auto *typeParam : *typeParamList) { > + // Visit the type parameter. > + if (Visit(MakeCXCursor(typeParam, TU, RegionOfInterest))) > + return true; > + > + // Visit the bound, if it's explicit. > + if (typeParam->hasExplicitBound()) { > + if (auto TInfo = typeParam->getTypeSourceInfo()) { > + if (Visit(TInfo->getTypeLoc())) > + return true; > + } > + } > + } > + > + return false; > +} > + > bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { > if (!D->isThisDeclarationADefinition()) { > // Forward declaration is treated like a reference. > return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU)); > } > > + // Objective-C type parameters. > + if (VisitObjCTypeParamList(D->getTypeParamListAsWritten())) > + return true; > + > // Issue callbacks for super class. > if (D->getSuperClass() && > Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), > @@ -1093,6 +1121,10 @@ bool CursorVisitor::VisitObjCInterfaceDe > TU))) > return true; > > + if (TypeSourceInfo *SuperClassTInfo = D->getSuperClassTInfo()) > + if (Visit(SuperClassTInfo->getTypeLoc())) > + return true; > + > ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); > for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), > E = D->protocol_end(); I != E; ++I, ++PL) > @@ -1486,6 +1518,11 @@ bool CursorVisitor::VisitObjCObjectTypeL > if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc())) > return true; > > + for (unsigned I = 0, N = TL.getNumTypeArgs(); I != N; ++I) { > + if (Visit(TL.getTypeArgTInfo(I)->getTypeLoc())) > + return true; > + } > + > for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { > if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), > TL.getProtocolLoc(I), > TU))) > @@ -4411,7 +4448,12 @@ static enum CXChildVisitResult GetCursor > *BestCursor = getTypeRefedCallExprCursor(*BestCursor); > return CXChildVisit_Recurse; > } > - > + > + // If we already have an Objective-C superclass reference, don't > + // update it further. > + if (BestCursor->kind == CXCursor_ObjCSuperClassRef) > + return CXChildVisit_Break; > + > *BestCursor = cursor; > return CXChildVisit_Recurse; > } > > Modified: cfe/trunk/tools/libclang/CursorVisitor.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CursorVisitor.h?rev=241542&r1=241541&r2=241542&view=diff > ============================================================================== > --- cfe/trunk/tools/libclang/CursorVisitor.h (original) > +++ cfe/trunk/tools/libclang/CursorVisitor.h Mon Jul 6 22:57:35 2015 > @@ -222,6 +222,7 @@ public: > bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); > bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); > bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); > + bool VisitObjCTypeParamList(ObjCTypeParamList *typeParamList); > bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); > bool VisitObjCImplDecl(ObjCImplDecl *D); > bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
