mirror of https://github.com/microsoft/clang.git
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters, and attach lists of type parameters to Objective-C classes, categories, forward declarations, and extensions as appropriate. Perform semantic analysis of type bounds for type parameters, both in isolation and across classes/categories/extensions to ensure consistency. Also handle (de-)serialization of Objective-C type parameter lists, along with sundry other things one must do to add a new declaration to Clang. Note that Objective-C type parameters are typedef name declarations, like typedefs and C++11 type aliases, in support of type erasure. Part of rdar://problem/6294649. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241541 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
27cac9536c
commit
5df68d34cd
|
@ -1307,7 +1307,12 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
|
DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
|
||||||
})
|
if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
|
||||||
|
for (auto typeParam : *typeParamList)
|
||||||
|
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
|
DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
|
||||||
})
|
})
|
||||||
|
@ -1316,7 +1321,12 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
|
DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
|
||||||
})
|
if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
|
||||||
|
for (auto typeParam : *typeParamList)
|
||||||
|
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
|
DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
|
||||||
})
|
})
|
||||||
|
@ -1335,6 +1345,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
|
||||||
|
if (D->hasExplicitBound()) {
|
||||||
|
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||||
|
// We shouldn't traverse D->getTypeForDecl(); it's a result of
|
||||||
|
// declaring the type alias, not something that was written in the
|
||||||
|
// source.
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
||||||
if (D->getTypeSourceInfo())
|
if (D->getTypeSourceInfo())
|
||||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||||
|
|
|
@ -501,6 +501,124 @@ public:
|
||||||
friend class ASTDeclWriter;
|
friend class ASTDeclWriter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Represents the declaration of an Objective-C type parameter.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// @interface NSDictionary<Key : id<NSCopying>, Value>
|
||||||
|
/// @end
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// In the example above, both \c Key and \c Value are represented by
|
||||||
|
/// \c ObjCTypeParamDecl. \c Key has an explicit bound of \c id<NSCopying>,
|
||||||
|
/// while \c Value gets an implicit bound of \c id.
|
||||||
|
///
|
||||||
|
/// Objective-C type parameters are typedef-names in the grammar,
|
||||||
|
class ObjCTypeParamDecl : public TypedefNameDecl {
|
||||||
|
void anchor() override;
|
||||||
|
|
||||||
|
// The location of the ':', which will be valid when the bound was
|
||||||
|
// explicitly specified.
|
||||||
|
SourceLocation ColonLoc;
|
||||||
|
|
||||||
|
ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc,
|
||||||
|
SourceLocation nameLoc, IdentifierInfo *name,
|
||||||
|
SourceLocation colonLoc, TypeSourceInfo *boundInfo)
|
||||||
|
: TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name,
|
||||||
|
boundInfo),
|
||||||
|
ColonLoc(colonLoc) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc,
|
||||||
|
SourceLocation nameLoc,
|
||||||
|
IdentifierInfo *name,
|
||||||
|
SourceLocation colonLoc,
|
||||||
|
TypeSourceInfo *boundInfo);
|
||||||
|
static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID);
|
||||||
|
|
||||||
|
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||||
|
|
||||||
|
/// Whether this type parameter has an explicitly-written type bound, e.g.,
|
||||||
|
/// "T : NSView".
|
||||||
|
bool hasExplicitBound() const { return ColonLoc.isValid(); }
|
||||||
|
|
||||||
|
/// Retrieve the location of the ':' separating the type parameter name
|
||||||
|
/// from the explicitly-specified bound.
|
||||||
|
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||||
|
|
||||||
|
// Implement isa/cast/dyncast/etc.
|
||||||
|
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||||
|
static bool classofKind(Kind K) { return K == ObjCTypeParam; }
|
||||||
|
|
||||||
|
friend class ASTDeclReader;
|
||||||
|
friend class ASTDeclWriter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Stores a list of Objective-C type parameters for a parameterized class
|
||||||
|
/// or a category/extension thereof.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// @interface NSArray<T> // stores the <T>
|
||||||
|
/// @end
|
||||||
|
/// \endcode
|
||||||
|
class ObjCTypeParamList {
|
||||||
|
union {
|
||||||
|
/// Location of the left and right angle brackets.
|
||||||
|
SourceRange Brackets;
|
||||||
|
|
||||||
|
// Used only for alignment.
|
||||||
|
ObjCTypeParamDecl *AlignmentHack;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The number of parameters in the list, which are tail-allocated.
|
||||||
|
unsigned NumParams;
|
||||||
|
|
||||||
|
ObjCTypeParamList(SourceLocation lAngleLoc,
|
||||||
|
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||||
|
SourceLocation rAngleLoc);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Create a new Objective-C type parameter list.
|
||||||
|
static ObjCTypeParamList *create(ASTContext &ctx,
|
||||||
|
SourceLocation lAngleLoc,
|
||||||
|
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||||
|
SourceLocation rAngleLoc);
|
||||||
|
|
||||||
|
/// Iterate through the type parameters in the list.
|
||||||
|
typedef ObjCTypeParamDecl **iterator;
|
||||||
|
|
||||||
|
iterator begin() { return reinterpret_cast<ObjCTypeParamDecl **>(this + 1); }
|
||||||
|
|
||||||
|
iterator end() { return begin() + size(); }
|
||||||
|
|
||||||
|
/// Determine the number of type parameters in this list.
|
||||||
|
unsigned size() const { return NumParams; }
|
||||||
|
|
||||||
|
// Iterate through the type parameters in the list.
|
||||||
|
typedef ObjCTypeParamDecl * const *const_iterator;
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
return reinterpret_cast<ObjCTypeParamDecl * const *>(this + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const {
|
||||||
|
return begin() + size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCTypeParamDecl *front() const {
|
||||||
|
assert(size() > 0 && "empty Objective-C type parameter list");
|
||||||
|
return *begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCTypeParamDecl *back() const {
|
||||||
|
assert(size() > 0 && "empty Objective-C type parameter list");
|
||||||
|
return *(end() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLocation getLAngleLoc() const { return Brackets.getBegin(); }
|
||||||
|
SourceLocation getRAngleLoc() const { return Brackets.getEnd(); }
|
||||||
|
SourceRange getSourceRange() const { return Brackets; }
|
||||||
|
};
|
||||||
|
|
||||||
/// ObjCContainerDecl - Represents a container for method declarations.
|
/// ObjCContainerDecl - Represents a container for method declarations.
|
||||||
/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl,
|
/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl,
|
||||||
/// ObjCProtocolDecl, and ObjCImplDecl.
|
/// ObjCProtocolDecl, and ObjCImplDecl.
|
||||||
|
@ -736,11 +854,15 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
|
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
|
||||||
IdentifierInfo *Id, SourceLocation CLoc,
|
IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
|
||||||
ObjCInterfaceDecl *PrevDecl, bool IsInternal);
|
SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
|
||||||
|
bool IsInternal);
|
||||||
|
|
||||||
void LoadExternalDefinition() const;
|
void LoadExternalDefinition() const;
|
||||||
|
|
||||||
|
/// The type parameters associated with this class, if any.
|
||||||
|
ObjCTypeParamList *TypeParamList;
|
||||||
|
|
||||||
/// \brief Contains a pointer to the data associated with this class,
|
/// \brief Contains a pointer to the data associated with this class,
|
||||||
/// which will be NULL if this class has not yet been defined.
|
/// which will be NULL if this class has not yet been defined.
|
||||||
///
|
///
|
||||||
|
@ -771,12 +893,27 @@ public:
|
||||||
static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC,
|
static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation atLoc,
|
SourceLocation atLoc,
|
||||||
IdentifierInfo *Id,
|
IdentifierInfo *Id,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
ObjCInterfaceDecl *PrevDecl,
|
ObjCInterfaceDecl *PrevDecl,
|
||||||
SourceLocation ClassLoc = SourceLocation(),
|
SourceLocation ClassLoc = SourceLocation(),
|
||||||
bool isInternal = false);
|
bool isInternal = false);
|
||||||
|
|
||||||
static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
|
static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
|
||||||
|
|
||||||
|
/// Retrieve the type parameters of this class.
|
||||||
|
///
|
||||||
|
/// This function looks for a type parameter list for the given
|
||||||
|
/// class; if the class has been declared (with @class) but not
|
||||||
|
/// defined (with @interface), it will search for a declaration that
|
||||||
|
/// has type parameters, skipping any declarations that do not.
|
||||||
|
ObjCTypeParamList *getTypeParamList() const;
|
||||||
|
|
||||||
|
/// Retrieve the type parameters written on this particular declaration of
|
||||||
|
/// the class.
|
||||||
|
ObjCTypeParamList *getTypeParamListAsWritten() const {
|
||||||
|
return TypeParamList;
|
||||||
|
}
|
||||||
|
|
||||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||||
if (isThisDeclarationADefinition())
|
if (isThisDeclarationADefinition())
|
||||||
return ObjCContainerDecl::getSourceRange();
|
return ObjCContainerDecl::getSourceRange();
|
||||||
|
@ -1719,6 +1856,9 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||||
/// Interface belonging to this category
|
/// Interface belonging to this category
|
||||||
ObjCInterfaceDecl *ClassInterface;
|
ObjCInterfaceDecl *ClassInterface;
|
||||||
|
|
||||||
|
/// The type parameters associated with this category, if any.
|
||||||
|
ObjCTypeParamList *TypeParamList;
|
||||||
|
|
||||||
/// referenced protocols in this category.
|
/// referenced protocols in this category.
|
||||||
ObjCProtocolList ReferencedProtocols;
|
ObjCProtocolList ReferencedProtocols;
|
||||||
|
|
||||||
|
@ -1736,13 +1876,9 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||||
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
||||||
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
|
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
|
||||||
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
|
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
SourceLocation IvarLBraceLoc=SourceLocation(),
|
SourceLocation IvarLBraceLoc=SourceLocation(),
|
||||||
SourceLocation IvarRBraceLoc=SourceLocation())
|
SourceLocation IvarRBraceLoc=SourceLocation());
|
||||||
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
|
||||||
ClassInterface(IDecl), NextClassCategory(nullptr),
|
|
||||||
CategoryNameLoc(CategoryNameLoc),
|
|
||||||
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -1752,6 +1888,7 @@ public:
|
||||||
SourceLocation CategoryNameLoc,
|
SourceLocation CategoryNameLoc,
|
||||||
IdentifierInfo *Id,
|
IdentifierInfo *Id,
|
||||||
ObjCInterfaceDecl *IDecl,
|
ObjCInterfaceDecl *IDecl,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
SourceLocation IvarLBraceLoc=SourceLocation(),
|
SourceLocation IvarLBraceLoc=SourceLocation(),
|
||||||
SourceLocation IvarRBraceLoc=SourceLocation());
|
SourceLocation IvarRBraceLoc=SourceLocation());
|
||||||
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||||
|
@ -1759,6 +1896,10 @@ public:
|
||||||
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
|
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
|
||||||
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
|
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
|
||||||
|
|
||||||
|
/// Retrieve the type parameter list associated with this category or
|
||||||
|
/// extension.
|
||||||
|
ObjCTypeParamList *getTypeParamList() const { return TypeParamList; }
|
||||||
|
|
||||||
ObjCCategoryImplDecl *getImplementation() const;
|
ObjCCategoryImplDecl *getImplementation() const;
|
||||||
void setImplementation(ObjCCategoryImplDecl *ImplD);
|
void setImplementation(ObjCCategoryImplDecl *ImplD);
|
||||||
|
|
||||||
|
|
|
@ -1382,7 +1382,11 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
|
DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
|
||||||
})
|
if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
|
||||||
|
for (auto typeParam : *typeParamList)
|
||||||
|
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
|
DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
|
||||||
})
|
})
|
||||||
|
@ -1391,7 +1395,11 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
|
DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
|
||||||
})
|
if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
|
||||||
|
for (auto typeParam : *typeParamList)
|
||||||
|
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
|
DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
|
||||||
})
|
})
|
||||||
|
@ -1410,6 +1418,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
|
||||||
|
if (D->hasExplicitBound()) {
|
||||||
|
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||||
|
// We shouldn't traverse D->getTypeForDecl(); it's a result of
|
||||||
|
// declaring the type alias, not something that was written in the
|
||||||
|
// source.
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
||||||
if (D->getTypeSourceInfo())
|
if (D->getTypeSourceInfo())
|
||||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||||
|
|
|
@ -21,6 +21,7 @@ def Named : Decl<1>;
|
||||||
def TypedefName : DDecl<Type, 1>;
|
def TypedefName : DDecl<Type, 1>;
|
||||||
def Typedef : DDecl<TypedefName>;
|
def Typedef : DDecl<TypedefName>;
|
||||||
def TypeAlias : DDecl<TypedefName>;
|
def TypeAlias : DDecl<TypedefName>;
|
||||||
|
def ObjCTypeParam : DDecl<TypedefName>;
|
||||||
def UnresolvedUsingTypename : DDecl<Type>;
|
def UnresolvedUsingTypename : DDecl<Type>;
|
||||||
def Tag : DDecl<Type, 1>, DeclContext;
|
def Tag : DDecl<Type, 1>, DeclContext;
|
||||||
def Enum : DDecl<Tag>;
|
def Enum : DDecl<Tag>;
|
||||||
|
|
|
@ -1017,4 +1017,17 @@ def err_module_expected_semi : Error<
|
||||||
"expected ';' after module name">;
|
"expected ';' after module name">;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let CategoryName = "Generics Issue" in {
|
||||||
|
|
||||||
|
def err_objc_expected_type_parameter : Error<
|
||||||
|
"expected type parameter name">;
|
||||||
|
|
||||||
|
def err_objc_parameterized_class_without_base : Error<
|
||||||
|
"parameterized Objective-C class %0 must have a superclass">;
|
||||||
|
|
||||||
|
def err_objc_parameterized_implementation : Error<
|
||||||
|
"@implementation cannot have type parameters">;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} // end of Parser diagnostics
|
} // end of Parser diagnostics
|
||||||
|
|
|
@ -7743,6 +7743,42 @@ def warn_nullability_missing : Warning<
|
||||||
"%select{pointer|block pointer|member pointer}0 is missing a nullability "
|
"%select{pointer|block pointer|member pointer}0 is missing a nullability "
|
||||||
"type specifier (_Nonnull, _Nullable, or _Null_unspecified)">,
|
"type specifier (_Nonnull, _Nullable, or _Null_unspecified)">,
|
||||||
InGroup<NullabilityCompleteness>;
|
InGroup<NullabilityCompleteness>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let CategoryName = "Generics Issue" in {
|
||||||
|
|
||||||
|
def err_objc_type_param_bound_nonobject : Error<
|
||||||
|
"type bound %0 for type parameter %1 is not an Objective-C pointer type">;
|
||||||
|
|
||||||
|
def err_objc_type_param_bound_missing_pointer : Error<
|
||||||
|
"missing '*' in type bound %0 for type parameter %1">;
|
||||||
|
|
||||||
|
def err_objc_type_param_redecl : Error<
|
||||||
|
"redeclaration of type parameter %0">;
|
||||||
|
|
||||||
|
def err_objc_type_param_arity_mismatch : Error<
|
||||||
|
"%select{forward class declaration|class definition|category|extension}0 has "
|
||||||
|
"too %select{few|many}1 type parameters (expected %2, have %3)">;
|
||||||
|
|
||||||
|
def err_objc_type_param_bound_conflict : Error<
|
||||||
|
"type bound %0 for type parameter %1 conflicts with "
|
||||||
|
"%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">;
|
||||||
|
|
||||||
|
def note_objc_type_param_here : Note<"type parameter %0 declared here">;
|
||||||
|
|
||||||
|
def err_objc_type_param_bound_missing : Error<
|
||||||
|
"missing type bound %0 for type parameter %1 in %select{@interface|@class}2">;
|
||||||
|
|
||||||
|
def err_objc_parameterized_category_nonclass : Error<
|
||||||
|
"%select{extension|category}0 of non-parameterized class %1 cannot have type "
|
||||||
|
"parameters">;
|
||||||
|
|
||||||
|
def err_objc_parameterized_forward_class : Error<
|
||||||
|
"forward declaration of non-parameterized class %0 cannot have type "
|
||||||
|
"parameters">;
|
||||||
|
|
||||||
|
def err_objc_parameterized_forward_class_first : Error<
|
||||||
|
"class %0 previously declared with type parameters">;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ namespace clang {
|
||||||
class PoisonSEHIdentifiersRAIIObject;
|
class PoisonSEHIdentifiersRAIIObject;
|
||||||
class VersionTuple;
|
class VersionTuple;
|
||||||
class OMPClause;
|
class OMPClause;
|
||||||
|
class ObjCTypeParamList;
|
||||||
|
class ObjCTypeParameter;
|
||||||
|
|
||||||
/// Parser - This implements a parser for the C family of languages. After
|
/// Parser - This implements a parser for the C family of languages. After
|
||||||
/// parsing units of the grammar, productions are invoked to handle whatever has
|
/// parsing units of the grammar, productions are invoked to handle whatever has
|
||||||
|
@ -1246,6 +1248,13 @@ private:
|
||||||
DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
|
DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
|
||||||
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||||
ParsedAttributes &prefixAttrs);
|
ParsedAttributes &prefixAttrs);
|
||||||
|
ObjCTypeParamList *parseObjCTypeParamList();
|
||||||
|
ObjCTypeParamList *parseObjCTypeParamListOrProtocolRefs(
|
||||||
|
SourceLocation &lAngleLoc,
|
||||||
|
SmallVectorImpl<IdentifierLocPair> &protocolIdents,
|
||||||
|
SourceLocation &rAngleLoc,
|
||||||
|
bool mayBeProtocolList = true);
|
||||||
|
|
||||||
void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
|
void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
|
||||||
BalancedDelimiterTracker &T,
|
BalancedDelimiterTracker &T,
|
||||||
SmallVectorImpl<Decl *> &AllIvarDecls,
|
SmallVectorImpl<Decl *> &AllIvarDecls,
|
||||||
|
@ -2469,7 +2478,8 @@ private:
|
||||||
typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
|
typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
|
||||||
|
|
||||||
bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
||||||
bool ConsumeLastToken);
|
bool ConsumeLastToken,
|
||||||
|
bool ObjCGenericList);
|
||||||
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
|
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
|
||||||
SourceLocation TemplateNameLoc,
|
SourceLocation TemplateNameLoc,
|
||||||
const CXXScopeSpec &SS,
|
const CXXScopeSpec &SS,
|
||||||
|
|
|
@ -7088,9 +7088,20 @@ public:
|
||||||
};
|
};
|
||||||
ObjCContainerKind getObjCContainerKind() const;
|
ObjCContainerKind getObjCContainerKind() const;
|
||||||
|
|
||||||
|
DeclResult actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
|
||||||
|
SourceLocation paramLoc,
|
||||||
|
SourceLocation colonLoc,
|
||||||
|
ParsedType typeBound);
|
||||||
|
|
||||||
|
ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc,
|
||||||
|
ArrayRef<Decl *> typeParams,
|
||||||
|
SourceLocation rAngleLoc);
|
||||||
|
void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList);
|
||||||
|
|
||||||
Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
||||||
IdentifierInfo *ClassName,
|
IdentifierInfo *ClassName,
|
||||||
SourceLocation ClassLoc,
|
SourceLocation ClassLoc,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
IdentifierInfo *SuperName,
|
IdentifierInfo *SuperName,
|
||||||
SourceLocation SuperLoc,
|
SourceLocation SuperLoc,
|
||||||
Decl * const *ProtoRefs,
|
Decl * const *ProtoRefs,
|
||||||
|
@ -7124,6 +7135,7 @@ public:
|
||||||
Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
||||||
IdentifierInfo *ClassName,
|
IdentifierInfo *ClassName,
|
||||||
SourceLocation ClassLoc,
|
SourceLocation ClassLoc,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
IdentifierInfo *CategoryName,
|
IdentifierInfo *CategoryName,
|
||||||
SourceLocation CategoryLoc,
|
SourceLocation CategoryLoc,
|
||||||
Decl * const *ProtoRefs,
|
Decl * const *ProtoRefs,
|
||||||
|
@ -7147,9 +7159,10 @@ public:
|
||||||
ArrayRef<Decl *> Decls);
|
ArrayRef<Decl *> Decls);
|
||||||
|
|
||||||
DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
|
DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
|
||||||
IdentifierInfo **IdentList,
|
IdentifierInfo **IdentList,
|
||||||
SourceLocation *IdentLocs,
|
SourceLocation *IdentLocs,
|
||||||
unsigned NumElts);
|
ArrayRef<ObjCTypeParamList *> TypeParamLists,
|
||||||
|
unsigned NumElts);
|
||||||
|
|
||||||
DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
|
DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
|
||||||
const IdentifierLocPair *IdentList,
|
const IdentifierLocPair *IdentList,
|
||||||
|
|
|
@ -413,6 +413,7 @@ namespace clang {
|
||||||
#define LINKAGESPEC(DERIVED, BASE)
|
#define LINKAGESPEC(DERIVED, BASE)
|
||||||
#define OBJCCOMPATIBLEALIAS(DERIVED, BASE)
|
#define OBJCCOMPATIBLEALIAS(DERIVED, BASE)
|
||||||
#define OBJCMETHOD(DERIVED, BASE)
|
#define OBJCMETHOD(DERIVED, BASE)
|
||||||
|
#define OBJCTYPEPARAM(DERIVED, BASE)
|
||||||
#define OBJCIVAR(DERIVED, BASE)
|
#define OBJCIVAR(DERIVED, BASE)
|
||||||
#define OBJCPROPERTY(DERIVED, BASE)
|
#define OBJCPROPERTY(DERIVED, BASE)
|
||||||
#define OBJCPROPERTYIMPL(DERIVED, BASE)
|
#define OBJCPROPERTYIMPL(DERIVED, BASE)
|
||||||
|
|
|
@ -1105,7 +1105,9 @@ namespace clang {
|
||||||
/// \brief An OMPThreadPrivateDecl record.
|
/// \brief An OMPThreadPrivateDecl record.
|
||||||
DECL_OMP_THREADPRIVATE,
|
DECL_OMP_THREADPRIVATE,
|
||||||
/// \brief An EmptyDecl record.
|
/// \brief An EmptyDecl record.
|
||||||
DECL_EMPTY
|
DECL_EMPTY,
|
||||||
|
/// \brief An ObjCTypeParamDecl record.
|
||||||
|
DECL_OBJC_TYPE_PARAM,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Record codes for each kind of statement or expression.
|
/// \brief Record codes for each kind of statement or expression.
|
||||||
|
|
|
@ -5951,6 +5951,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
|
||||||
= ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
|
= ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
&Idents.get("Protocol"),
|
&Idents.get("Protocol"),
|
||||||
|
/*typeParamList=*/nullptr,
|
||||||
/*PrevDecl=*/nullptr,
|
/*PrevDecl=*/nullptr,
|
||||||
SourceLocation(), true);
|
SourceLocation(), true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,6 +240,9 @@ namespace {
|
||||||
void dumpTemplateArgument(const TemplateArgument &A,
|
void dumpTemplateArgument(const TemplateArgument &A,
|
||||||
SourceRange R = SourceRange());
|
SourceRange R = SourceRange());
|
||||||
|
|
||||||
|
// Objective-C utilities.
|
||||||
|
void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams);
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
void VisitComplexType(const ComplexType *T) {
|
void VisitComplexType(const ComplexType *T) {
|
||||||
dumpTypeAsChild(T->getElementType());
|
dumpTypeAsChild(T->getElementType());
|
||||||
|
@ -463,6 +466,7 @@ namespace {
|
||||||
// ObjC Decls
|
// ObjC Decls
|
||||||
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
|
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
|
||||||
void VisitObjCMethodDecl(const ObjCMethodDecl *D);
|
void VisitObjCMethodDecl(const ObjCMethodDecl *D);
|
||||||
|
void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
|
||||||
void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
|
void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
|
||||||
void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
|
void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
|
||||||
void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
|
void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
|
||||||
|
@ -954,6 +958,18 @@ void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Objective-C Utilities
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
|
||||||
|
if (!typeParams)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto typeParam : *typeParams) {
|
||||||
|
dumpDecl(typeParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Decl dumping methods.
|
// Decl dumping methods.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -1457,9 +1473,17 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
|
||||||
dumpStmt(D->getBody());
|
dumpStmt(D->getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
|
||||||
|
dumpName(D);
|
||||||
|
if (D->hasExplicitBound())
|
||||||
|
OS << " bounded";
|
||||||
|
dumpType(D->getUnderlyingType());
|
||||||
|
}
|
||||||
|
|
||||||
void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
|
void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
|
||||||
dumpName(D);
|
dumpName(D);
|
||||||
dumpDeclRef(D->getClassInterface());
|
dumpDeclRef(D->getClassInterface());
|
||||||
|
dumpObjCTypeParamList(D->getTypeParamList());
|
||||||
dumpDeclRef(D->getImplementation());
|
dumpDeclRef(D->getImplementation());
|
||||||
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
|
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
|
||||||
E = D->protocol_end();
|
E = D->protocol_end();
|
||||||
|
@ -1482,6 +1506,7 @@ void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
|
||||||
|
|
||||||
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
|
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
|
||||||
dumpName(D);
|
dumpName(D);
|
||||||
|
dumpObjCTypeParamList(D->getTypeParamListAsWritten());
|
||||||
dumpDeclRef(D->getSuperClass(), "super");
|
dumpDeclRef(D->getSuperClass(), "super");
|
||||||
|
|
||||||
dumpDeclRef(D->getImplementation());
|
dumpDeclRef(D->getImplementation());
|
||||||
|
|
|
@ -150,9 +150,12 @@ namespace clang {
|
||||||
Decl *VisitImplicitParamDecl(ImplicitParamDecl *D);
|
Decl *VisitImplicitParamDecl(ImplicitParamDecl *D);
|
||||||
Decl *VisitParmVarDecl(ParmVarDecl *D);
|
Decl *VisitParmVarDecl(ParmVarDecl *D);
|
||||||
Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
|
Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
|
||||||
|
Decl *VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
|
||||||
Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D);
|
Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D);
|
||||||
Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
|
Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
|
||||||
Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D);
|
Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D);
|
||||||
|
|
||||||
|
ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list);
|
||||||
Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
||||||
Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
|
Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
|
||||||
Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
|
Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
|
||||||
|
@ -3423,6 +3426,32 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
|
||||||
return ToMethod;
|
return ToMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
|
||||||
|
// Import the major distinguishing characteristics of a category.
|
||||||
|
DeclContext *DC, *LexicalDC;
|
||||||
|
DeclarationName Name;
|
||||||
|
SourceLocation Loc;
|
||||||
|
NamedDecl *ToD;
|
||||||
|
if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
|
||||||
|
return nullptr;
|
||||||
|
if (ToD)
|
||||||
|
return ToD;
|
||||||
|
|
||||||
|
TypeSourceInfo *BoundInfo = Importer.Import(D->getTypeSourceInfo());
|
||||||
|
if (!BoundInfo)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create(
|
||||||
|
Importer.getToContext(), DC,
|
||||||
|
Importer.Import(D->getLocation()),
|
||||||
|
Name.getAsIdentifierInfo(),
|
||||||
|
Importer.Import(D->getColonLoc()),
|
||||||
|
BoundInfo);
|
||||||
|
Importer.Imported(D, Result);
|
||||||
|
Result->setLexicalDeclContext(LexicalDC);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
||||||
// Import the major distinguishing characteristics of a category.
|
// Import the major distinguishing characteristics of a category.
|
||||||
DeclContext *DC, *LexicalDC;
|
DeclContext *DC, *LexicalDC;
|
||||||
|
@ -3450,6 +3479,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
||||||
Importer.Import(D->getCategoryNameLoc()),
|
Importer.Import(D->getCategoryNameLoc()),
|
||||||
Name.getAsIdentifierInfo(),
|
Name.getAsIdentifierInfo(),
|
||||||
ToInterface,
|
ToInterface,
|
||||||
|
ImportObjCTypeParamList(
|
||||||
|
D->getTypeParamList()),
|
||||||
Importer.Import(D->getIvarLBraceLoc()),
|
Importer.Import(D->getIvarLBraceLoc()),
|
||||||
Importer.Import(D->getIvarRBraceLoc()));
|
Importer.Import(D->getIvarRBraceLoc()));
|
||||||
ToCategory->setLexicalDeclContext(LexicalDC);
|
ToCategory->setLexicalDeclContext(LexicalDC);
|
||||||
|
@ -3716,6 +3747,27 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjCTypeParamList *
|
||||||
|
ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) {
|
||||||
|
if (!list)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
SmallVector<ObjCTypeParamDecl *, 4> toTypeParams;
|
||||||
|
for (auto fromTypeParam : *list) {
|
||||||
|
auto toTypeParam = cast_or_null<ObjCTypeParamDecl>(
|
||||||
|
Importer.Import(fromTypeParam));
|
||||||
|
if (!toTypeParam)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
toTypeParams.push_back(toTypeParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjCTypeParamList::create(Importer.getToContext(),
|
||||||
|
Importer.Import(list->getLAngleLoc()),
|
||||||
|
toTypeParams,
|
||||||
|
Importer.Import(list->getRAngleLoc()));
|
||||||
|
}
|
||||||
|
|
||||||
Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
||||||
// If this class has a definition in the translation unit we're coming from,
|
// If this class has a definition in the translation unit we're coming from,
|
||||||
// but this particular declaration is not that definition, import the
|
// but this particular declaration is not that definition, import the
|
||||||
|
@ -3756,7 +3808,9 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
||||||
if (!ToIface) {
|
if (!ToIface) {
|
||||||
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
|
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
|
||||||
Importer.Import(D->getAtStartLoc()),
|
Importer.Import(D->getAtStartLoc()),
|
||||||
Name.getAsIdentifierInfo(),
|
Name.getAsIdentifierInfo(),
|
||||||
|
ImportObjCTypeParamList(
|
||||||
|
D->getTypeParamListAsWritten()),
|
||||||
/*PrevDecl=*/nullptr, Loc,
|
/*PrevDecl=*/nullptr, Loc,
|
||||||
D->isImplicitInterfaceDecl());
|
D->isImplicitInterfaceDecl());
|
||||||
ToIface->setLexicalDeclContext(LexicalDC);
|
ToIface->setLexicalDeclContext(LexicalDC);
|
||||||
|
|
|
@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
||||||
case TypeAliasTemplate:
|
case TypeAliasTemplate:
|
||||||
case UnresolvedUsingTypename:
|
case UnresolvedUsingTypename:
|
||||||
case TemplateTypeParm:
|
case TemplateTypeParm:
|
||||||
|
case ObjCTypeParam:
|
||||||
return IDNS_Ordinary | IDNS_Type;
|
return IDNS_Ordinary | IDNS_Type;
|
||||||
|
|
||||||
case UsingShadow:
|
case UsingShadow:
|
||||||
|
|
|
@ -239,6 +239,26 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
|
||||||
|
|
||||||
void ObjCInterfaceDecl::anchor() { }
|
void ObjCInterfaceDecl::anchor() { }
|
||||||
|
|
||||||
|
ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const {
|
||||||
|
// If this particular declaration has a type parameter list, return it.
|
||||||
|
if (ObjCTypeParamList *written = getTypeParamListAsWritten())
|
||||||
|
return written;
|
||||||
|
|
||||||
|
// If there is a definition, return its type parameter list.
|
||||||
|
if (const ObjCInterfaceDecl *def = getDefinition())
|
||||||
|
return def->getTypeParamListAsWritten();
|
||||||
|
|
||||||
|
// Otherwise, look at previous declarations to determine whether any
|
||||||
|
// of them has a type parameter list, skipping over those
|
||||||
|
// declarations that do not.
|
||||||
|
for (auto decl = getPreviousDecl(); decl; decl = decl->getPreviousDecl()) {
|
||||||
|
if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten())
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
|
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
|
||||||
/// with name 'PropertyId' in the primary class; including those in protocols
|
/// with name 'PropertyId' in the primary class; including those in protocols
|
||||||
/// (direct or indirect) used by the primary class.
|
/// (direct or indirect) used by the primary class.
|
||||||
|
@ -1136,6 +1156,62 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// ObjCTypeParamDecl
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
void ObjCTypeParamDecl::anchor() { }
|
||||||
|
|
||||||
|
ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc,
|
||||||
|
SourceLocation nameLoc,
|
||||||
|
IdentifierInfo *name,
|
||||||
|
SourceLocation colonLoc,
|
||||||
|
TypeSourceInfo *boundInfo) {
|
||||||
|
return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, nameLoc, name, colonLoc,
|
||||||
|
boundInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
|
||||||
|
unsigned ID) {
|
||||||
|
return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, SourceLocation(),
|
||||||
|
nullptr, SourceLocation(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceRange ObjCTypeParamDecl::getSourceRange() const {
|
||||||
|
if (hasExplicitBound()) {
|
||||||
|
return SourceRange(getLocation(),
|
||||||
|
getTypeSourceInfo()->getTypeLoc().getEndLoc());
|
||||||
|
}
|
||||||
|
|
||||||
|
return SourceRange(getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// ObjCTypeParamList
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc,
|
||||||
|
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||||
|
SourceLocation rAngleLoc)
|
||||||
|
: Brackets(lAngleLoc, rAngleLoc), NumParams(typeParams.size())
|
||||||
|
{
|
||||||
|
std::copy(typeParams.begin(), typeParams.end(), begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ObjCTypeParamList *ObjCTypeParamList::create(
|
||||||
|
ASTContext &ctx,
|
||||||
|
SourceLocation lAngleLoc,
|
||||||
|
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||||
|
SourceLocation rAngleLoc) {
|
||||||
|
unsigned size = sizeof(ObjCTypeParamList)
|
||||||
|
+ sizeof(ObjCTypeParamDecl *) * typeParams.size();
|
||||||
|
static_assert(alignof(ObjCTypeParamList) >= alignof(ObjCTypeParamDecl*),
|
||||||
|
"type parameter list needs greater alignment");
|
||||||
|
unsigned align = llvm::alignOf<ObjCTypeParamList>();
|
||||||
|
void *mem = ctx.Allocate(size, align);
|
||||||
|
return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc);
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ObjCInterfaceDecl
|
// ObjCInterfaceDecl
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -1144,11 +1220,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
|
||||||
DeclContext *DC,
|
DeclContext *DC,
|
||||||
SourceLocation atLoc,
|
SourceLocation atLoc,
|
||||||
IdentifierInfo *Id,
|
IdentifierInfo *Id,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
ObjCInterfaceDecl *PrevDecl,
|
ObjCInterfaceDecl *PrevDecl,
|
||||||
SourceLocation ClassLoc,
|
SourceLocation ClassLoc,
|
||||||
bool isInternal){
|
bool isInternal){
|
||||||
ObjCInterfaceDecl *Result = new (C, DC)
|
ObjCInterfaceDecl *Result = new (C, DC)
|
||||||
ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal);
|
ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
|
||||||
|
isInternal);
|
||||||
Result->Data.setInt(!C.getLangOpts().Modules);
|
Result->Data.setInt(!C.getLangOpts().Modules);
|
||||||
C.getObjCInterfaceType(Result, PrevDecl);
|
C.getObjCInterfaceType(Result, PrevDecl);
|
||||||
return Result;
|
return Result;
|
||||||
|
@ -1159,6 +1237,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
|
||||||
ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr,
|
ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr,
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
nullptr,
|
nullptr,
|
||||||
|
nullptr,
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
nullptr, false);
|
nullptr, false);
|
||||||
Result->Data.setInt(!C.getLangOpts().Modules);
|
Result->Data.setInt(!C.getLangOpts().Modules);
|
||||||
|
@ -1167,11 +1246,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
|
||||||
|
|
||||||
ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
|
ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation AtLoc, IdentifierInfo *Id,
|
SourceLocation AtLoc, IdentifierInfo *Id,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
SourceLocation CLoc,
|
SourceLocation CLoc,
|
||||||
ObjCInterfaceDecl *PrevDecl,
|
ObjCInterfaceDecl *PrevDecl,
|
||||||
bool IsInternal)
|
bool IsInternal)
|
||||||
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
|
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
|
||||||
redeclarable_base(C), TypeForDecl(nullptr), Data() {
|
redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(typeParamList),
|
||||||
|
Data() {
|
||||||
setPreviousDecl(PrevDecl);
|
setPreviousDecl(PrevDecl);
|
||||||
|
|
||||||
// Copy the 'data' pointer over.
|
// Copy the 'data' pointer over.
|
||||||
|
@ -1179,6 +1260,12 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
|
||||||
Data = PrevDecl->Data;
|
Data = PrevDecl->Data;
|
||||||
|
|
||||||
setImplicit(IsInternal);
|
setImplicit(IsInternal);
|
||||||
|
|
||||||
|
// Update the declaration context of the type parameters.
|
||||||
|
if (typeParamList) {
|
||||||
|
for (auto typeParam : *typeParamList)
|
||||||
|
typeParam->setDeclContext(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjCInterfaceDecl::LoadExternalDefinition() const {
|
void ObjCInterfaceDecl::LoadExternalDefinition() const {
|
||||||
|
@ -1648,17 +1735,39 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
|
||||||
|
|
||||||
void ObjCCategoryDecl::anchor() { }
|
void ObjCCategoryDecl::anchor() { }
|
||||||
|
|
||||||
|
ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
||||||
|
SourceLocation ClassNameLoc,
|
||||||
|
SourceLocation CategoryNameLoc,
|
||||||
|
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
|
SourceLocation IvarLBraceLoc,
|
||||||
|
SourceLocation IvarRBraceLoc)
|
||||||
|
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
||||||
|
ClassInterface(IDecl), TypeParamList(typeParamList),
|
||||||
|
NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc),
|
||||||
|
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc)
|
||||||
|
{
|
||||||
|
// Set the declaration context of each of the type parameters.
|
||||||
|
if (typeParamList) {
|
||||||
|
for (auto typeParam : *typeParamList) {
|
||||||
|
typeParam->setDeclContext(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
|
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation AtLoc,
|
SourceLocation AtLoc,
|
||||||
SourceLocation ClassNameLoc,
|
SourceLocation ClassNameLoc,
|
||||||
SourceLocation CategoryNameLoc,
|
SourceLocation CategoryNameLoc,
|
||||||
IdentifierInfo *Id,
|
IdentifierInfo *Id,
|
||||||
ObjCInterfaceDecl *IDecl,
|
ObjCInterfaceDecl *IDecl,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
SourceLocation IvarLBraceLoc,
|
SourceLocation IvarLBraceLoc,
|
||||||
SourceLocation IvarRBraceLoc) {
|
SourceLocation IvarRBraceLoc) {
|
||||||
ObjCCategoryDecl *CatDecl =
|
ObjCCategoryDecl *CatDecl =
|
||||||
new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
|
new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
|
||||||
IDecl, IvarLBraceLoc, IvarRBraceLoc);
|
IDecl, typeParamList, IvarLBraceLoc,
|
||||||
|
IvarRBraceLoc);
|
||||||
if (IDecl) {
|
if (IDecl) {
|
||||||
// Link this category into its class's category list.
|
// Link this category into its class's category list.
|
||||||
CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
|
CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
|
||||||
|
@ -1676,7 +1785,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
|
||||||
unsigned ID) {
|
unsigned ID) {
|
||||||
return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
|
return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
|
||||||
SourceLocation(), SourceLocation(),
|
SourceLocation(), SourceLocation(),
|
||||||
nullptr, nullptr);
|
nullptr, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
|
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
|
||||||
|
|
|
@ -44,6 +44,8 @@ namespace {
|
||||||
void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
|
void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
|
||||||
QualType T);
|
QualType T);
|
||||||
|
|
||||||
|
void PrintObjCTypeParams(ObjCTypeParamList *Params);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
|
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
|
||||||
unsigned Indentation = 0, bool PrintInstantiation = false)
|
unsigned Indentation = 0, bool PrintInstantiation = false)
|
||||||
|
@ -962,6 +964,25 @@ void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx,
|
||||||
Out << ')';
|
Out << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) {
|
||||||
|
Out << "<";
|
||||||
|
unsigned First = true;
|
||||||
|
for (auto *Param : *Params) {
|
||||||
|
if (First) {
|
||||||
|
First = false;
|
||||||
|
} else {
|
||||||
|
Out << ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
Out << Param->getDeclName().getAsString();
|
||||||
|
|
||||||
|
if (Param->hasExplicitBound()) {
|
||||||
|
Out << " : " << Param->getUnderlyingType().getAsString(Policy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Out << ">";
|
||||||
|
}
|
||||||
|
|
||||||
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
|
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
|
||||||
if (OMD->isInstanceMethod())
|
if (OMD->isInstanceMethod())
|
||||||
Out << "- ";
|
Out << "- ";
|
||||||
|
@ -1037,14 +1058,24 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
|
||||||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||||
|
|
||||||
if (!OID->isThisDeclarationADefinition()) {
|
if (!OID->isThisDeclarationADefinition()) {
|
||||||
Out << "@class " << I << ";";
|
Out << "@class " << I;
|
||||||
|
|
||||||
|
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
|
||||||
|
PrintObjCTypeParams(TypeParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Out << ";";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool eolnOut = false;
|
bool eolnOut = false;
|
||||||
|
Out << "@interface " << I;
|
||||||
|
|
||||||
|
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
|
||||||
|
PrintObjCTypeParams(TypeParams);
|
||||||
|
}
|
||||||
|
|
||||||
if (SID)
|
if (SID)
|
||||||
Out << "@interface " << I << " : " << *SID;
|
Out << " : " << OID->getSuperClass()->getName();
|
||||||
else
|
|
||||||
Out << "@interface " << I;
|
|
||||||
|
|
||||||
// Protocols?
|
// Protocols?
|
||||||
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
|
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
|
||||||
|
@ -1107,7 +1138,11 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
|
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
|
||||||
Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
|
Out << "@interface " << *PID->getClassInterface();
|
||||||
|
if (auto TypeParams = PID->getTypeParamList()) {
|
||||||
|
PrintObjCTypeParams(TypeParams);
|
||||||
|
}
|
||||||
|
Out << "(" << *PID << ")\n";
|
||||||
if (PID->ivar_size() > 0) {
|
if (PID->ivar_size() > 0) {
|
||||||
Out << "{\n";
|
Out << "{\n";
|
||||||
Indentation += Policy.Indentation;
|
Indentation += Policy.Indentation;
|
||||||
|
|
|
@ -79,6 +79,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
||||||
case Decl::Captured:
|
case Decl::Captured:
|
||||||
case Decl::ClassScopeFunctionSpecialization:
|
case Decl::ClassScopeFunctionSpecialization:
|
||||||
case Decl::UsingShadow:
|
case Decl::UsingShadow:
|
||||||
|
case Decl::ObjCTypeParam:
|
||||||
llvm_unreachable("Declaration should not be in declstmts!");
|
llvm_unreachable("Declaration should not be in declstmts!");
|
||||||
case Decl::Function: // void X();
|
case Decl::Function: // void X();
|
||||||
case Decl::Record: // struct/union/class X;
|
case Decl::Record: // struct/union/class X;
|
||||||
|
|
|
@ -96,14 +96,17 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
|
||||||
|
|
||||||
///
|
///
|
||||||
/// objc-class-declaration:
|
/// objc-class-declaration:
|
||||||
/// '@' 'class' identifier-list ';'
|
/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
|
||||||
|
///
|
||||||
|
/// objc-class-forward-decl:
|
||||||
|
/// identifier objc-type-parameter-list[opt]
|
||||||
///
|
///
|
||||||
Parser::DeclGroupPtrTy
|
Parser::DeclGroupPtrTy
|
||||||
Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
||||||
ConsumeToken(); // the identifier "class"
|
ConsumeToken(); // the identifier "class"
|
||||||
SmallVector<IdentifierInfo *, 8> ClassNames;
|
SmallVector<IdentifierInfo *, 8> ClassNames;
|
||||||
SmallVector<SourceLocation, 8> ClassLocs;
|
SmallVector<SourceLocation, 8> ClassLocs;
|
||||||
|
SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
MaybeSkipAttributes(tok::objc_class);
|
MaybeSkipAttributes(tok::objc_class);
|
||||||
|
@ -116,6 +119,14 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
||||||
ClassLocs.push_back(Tok.getLocation());
|
ClassLocs.push_back(Tok.getLocation());
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
|
|
||||||
|
// Parse the optional objc-type-parameter-list.
|
||||||
|
ObjCTypeParamList *TypeParams = nullptr;
|
||||||
|
if (Tok.is(tok::less)) {
|
||||||
|
TypeParams = parseObjCTypeParamList();
|
||||||
|
if (TypeParams)
|
||||||
|
Actions.popObjCTypeParamList(getCurScope(), TypeParams);
|
||||||
|
}
|
||||||
|
ClassTypeParams.push_back(TypeParams);
|
||||||
if (!TryConsumeToken(tok::comma))
|
if (!TryConsumeToken(tok::comma))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -126,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
||||||
|
|
||||||
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
|
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
|
||||||
ClassLocs.data(),
|
ClassLocs.data(),
|
||||||
|
ClassTypeParams,
|
||||||
ClassNames.size());
|
ClassNames.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,15 +166,15 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
|
||||||
/// objc-category-interface
|
/// objc-category-interface
|
||||||
///
|
///
|
||||||
/// objc-class-interface:
|
/// objc-class-interface:
|
||||||
/// '@' 'interface' identifier objc-superclass[opt]
|
/// '@' 'interface' identifier objc-type-parameter-list[opt]
|
||||||
/// objc-protocol-refs[opt]
|
/// objc-superclass[opt] objc-protocol-refs[opt]
|
||||||
/// objc-class-instance-variables[opt]
|
/// objc-class-instance-variables[opt]
|
||||||
/// objc-interface-decl-list
|
/// objc-interface-decl-list
|
||||||
/// @end
|
/// @end
|
||||||
///
|
///
|
||||||
/// objc-category-interface:
|
/// objc-category-interface:
|
||||||
/// '@' 'interface' identifier '(' identifier[opt] ')'
|
/// '@' 'interface' identifier objc-type-parameter-list[opt]
|
||||||
/// objc-protocol-refs[opt]
|
/// '(' identifier[opt] ')' objc-protocol-refs[opt]
|
||||||
/// objc-interface-decl-list
|
/// objc-interface-decl-list
|
||||||
/// @end
|
/// @end
|
||||||
///
|
///
|
||||||
|
@ -202,7 +214,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||||
// We have a class or category name - consume it.
|
// We have a class or category name - consume it.
|
||||||
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
||||||
SourceLocation nameLoc = ConsumeToken();
|
SourceLocation nameLoc = ConsumeToken();
|
||||||
if (Tok.is(tok::l_paren) &&
|
|
||||||
|
// Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
|
||||||
|
// case, LAngleLoc will be valid and ProtocolIdents will capture the
|
||||||
|
// protocol references (that have not yet been resolved).
|
||||||
|
SourceLocation LAngleLoc, EndProtoLoc;
|
||||||
|
SmallVector<IdentifierLocPair, 8> ProtocolIdents;
|
||||||
|
ObjCTypeParamList *typeParameterList = nullptr;
|
||||||
|
if (Tok.is(tok::less)) {
|
||||||
|
typeParameterList = parseObjCTypeParamListOrProtocolRefs(LAngleLoc,
|
||||||
|
ProtocolIdents,
|
||||||
|
EndProtoLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tok.is(tok::l_paren) &&
|
||||||
!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
|
!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
|
||||||
|
|
||||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||||
|
@ -237,7 +262,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, we need to check for any protocol references.
|
// Next, we need to check for any protocol references.
|
||||||
SourceLocation LAngleLoc, EndProtoLoc;
|
assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
|
||||||
SmallVector<Decl *, 8> ProtocolRefs;
|
SmallVector<Decl *, 8> ProtocolRefs;
|
||||||
SmallVector<SourceLocation, 8> ProtocolLocs;
|
SmallVector<SourceLocation, 8> ProtocolLocs;
|
||||||
if (Tok.is(tok::less) &&
|
if (Tok.is(tok::less) &&
|
||||||
|
@ -248,6 +273,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||||
Decl *CategoryType =
|
Decl *CategoryType =
|
||||||
Actions.ActOnStartCategoryInterface(AtLoc,
|
Actions.ActOnStartCategoryInterface(AtLoc,
|
||||||
nameId, nameLoc,
|
nameId, nameLoc,
|
||||||
|
typeParameterList,
|
||||||
categoryId, categoryLoc,
|
categoryId, categoryLoc,
|
||||||
ProtocolRefs.data(),
|
ProtocolRefs.data(),
|
||||||
ProtocolRefs.size(),
|
ProtocolRefs.size(),
|
||||||
|
@ -258,6 +284,10 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||||
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
|
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
|
||||||
|
|
||||||
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
|
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
|
||||||
|
|
||||||
|
if (typeParameterList)
|
||||||
|
Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
|
||||||
|
|
||||||
return CategoryType;
|
return CategoryType;
|
||||||
}
|
}
|
||||||
// Parse a class interface.
|
// Parse a class interface.
|
||||||
|
@ -281,21 +311,44 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||||
}
|
}
|
||||||
superClassId = Tok.getIdentifierInfo();
|
superClassId = Tok.getIdentifierInfo();
|
||||||
superClassLoc = ConsumeToken();
|
superClassLoc = ConsumeToken();
|
||||||
|
} else if (typeParameterList) {
|
||||||
|
// An objc-type-parameter-list is ambiguous with an objc-protocol-refs
|
||||||
|
// in an @interface without a specified superclass, so such classes
|
||||||
|
// are ill-formed. We have determined that we have an
|
||||||
|
// objc-type-parameter-list but no superclass, so complain and record
|
||||||
|
// as if we inherited from NSObject.
|
||||||
|
SourceLocation insertLoc = PP.getLocForEndOfToken(PrevTokLocation);
|
||||||
|
Diag(insertLoc, diag::err_objc_parameterized_class_without_base)
|
||||||
|
<< nameId
|
||||||
|
<< FixItHint::CreateInsertion(insertLoc, " : NSObject");
|
||||||
|
superClassId = PP.getIdentifierInfo("NSObject");
|
||||||
|
superClassLoc = Tok.getLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, we need to check for any protocol references.
|
// Next, we need to check for any protocol references.
|
||||||
SmallVector<Decl *, 8> ProtocolRefs;
|
SmallVector<Decl *, 8> ProtocolRefs;
|
||||||
SmallVector<SourceLocation, 8> ProtocolLocs;
|
SmallVector<SourceLocation, 8> ProtocolLocs;
|
||||||
SourceLocation LAngleLoc, EndProtoLoc;
|
if (LAngleLoc.isValid()) {
|
||||||
if (Tok.is(tok::less) &&
|
// We already parsed the protocols named when we thought we had a
|
||||||
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
|
// type parameter list. Translate them into actual protocol references.
|
||||||
LAngleLoc, EndProtoLoc))
|
for (const auto &pair : ProtocolIdents) {
|
||||||
|
ProtocolLocs.push_back(pair.second);
|
||||||
|
}
|
||||||
|
Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
|
||||||
|
/*ForObjCContainer=*/true,
|
||||||
|
&ProtocolIdents[0], ProtocolIdents.size(),
|
||||||
|
ProtocolRefs);
|
||||||
|
} else if (Tok.is(tok::less) &&
|
||||||
|
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
|
||||||
|
LAngleLoc, EndProtoLoc)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (Tok.isNot(tok::less))
|
if (Tok.isNot(tok::less))
|
||||||
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
|
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
|
||||||
|
|
||||||
Decl *ClsType =
|
Decl *ClsType =
|
||||||
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
|
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList,
|
||||||
superClassId, superClassLoc,
|
superClassId, superClassLoc,
|
||||||
ProtocolRefs.data(), ProtocolRefs.size(),
|
ProtocolRefs.data(), ProtocolRefs.size(),
|
||||||
ProtocolLocs.data(),
|
ProtocolLocs.data(),
|
||||||
|
@ -305,6 +358,10 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||||
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
|
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
|
||||||
|
|
||||||
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
|
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
|
||||||
|
|
||||||
|
if (typeParameterList)
|
||||||
|
Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
|
||||||
|
|
||||||
return ClsType;
|
return ClsType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,6 +396,172 @@ static void addContextSensitiveTypeNullability(Parser &P,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an Objective-C type parameter list, if present, or capture
|
||||||
|
/// the locations of the protocol identifiers for a list of protocol
|
||||||
|
/// references.
|
||||||
|
///
|
||||||
|
/// objc-type-parameter-list:
|
||||||
|
/// '<' objc-type-parameter (',' objc-type-parameter)* '>'
|
||||||
|
///
|
||||||
|
/// objc-type-parameter:
|
||||||
|
/// identifier objc-type-parameter-bound[opt]
|
||||||
|
///
|
||||||
|
/// objc-type-parameter-bound:
|
||||||
|
/// ':' type-name
|
||||||
|
///
|
||||||
|
/// \param lAngleLoc The location of the starting '<'.
|
||||||
|
///
|
||||||
|
/// \param protocolIdents Will capture the list of identifiers, if the
|
||||||
|
/// angle brackets contain a list of protocol references rather than a
|
||||||
|
/// type parameter list.
|
||||||
|
///
|
||||||
|
/// \param rAngleLoc The location of the ending '>'.
|
||||||
|
ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
|
||||||
|
SourceLocation &lAngleLoc,
|
||||||
|
SmallVectorImpl<IdentifierLocPair> &protocolIdents,
|
||||||
|
SourceLocation &rAngleLoc,
|
||||||
|
bool mayBeProtocolList) {
|
||||||
|
assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
|
||||||
|
|
||||||
|
// Within the type parameter list, don't treat '>' as an operator.
|
||||||
|
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
|
||||||
|
|
||||||
|
// Local function to "flush" the protocol identifiers, turning them into
|
||||||
|
// type parameters.
|
||||||
|
SmallVector<Decl *, 4> typeParams;
|
||||||
|
auto makeProtocolIdentsIntoTypeParameters = [&]() {
|
||||||
|
for (const auto &pair : protocolIdents) {
|
||||||
|
DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
|
||||||
|
pair.first,
|
||||||
|
pair.second,
|
||||||
|
SourceLocation(),
|
||||||
|
ParsedType());
|
||||||
|
if (typeParam.isUsable())
|
||||||
|
typeParams.push_back(typeParam.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
protocolIdents.clear();
|
||||||
|
mayBeProtocolList = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool invalid = false;
|
||||||
|
lAngleLoc = ConsumeToken();
|
||||||
|
do {
|
||||||
|
// Parse the identifier.
|
||||||
|
if (!Tok.is(tok::identifier)) {
|
||||||
|
// Code completion.
|
||||||
|
if (Tok.is(tok::code_completion)) {
|
||||||
|
// FIXME: If these aren't protocol references, we'll need different
|
||||||
|
// completions.
|
||||||
|
Actions.CodeCompleteObjCProtocolReferences(protocolIdents.data(),
|
||||||
|
protocolIdents.size());
|
||||||
|
cutOffParsing();
|
||||||
|
|
||||||
|
// FIXME: Better recovery here?.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Diag(Tok, diag::err_objc_expected_type_parameter);
|
||||||
|
invalid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentifierInfo *paramName = Tok.getIdentifierInfo();
|
||||||
|
SourceLocation paramLoc = ConsumeToken();
|
||||||
|
|
||||||
|
// If there is a bound, parse it.
|
||||||
|
SourceLocation colonLoc;
|
||||||
|
TypeResult boundType;
|
||||||
|
if (TryConsumeToken(tok::colon, colonLoc)) {
|
||||||
|
// Once we've seen a bound, we know this is not a list of protocol
|
||||||
|
// references.
|
||||||
|
if (mayBeProtocolList) {
|
||||||
|
// Up until now, we have been queuing up parameters because they
|
||||||
|
// might be protocol references. Turn them into parameters now.
|
||||||
|
makeProtocolIdentsIntoTypeParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
// type-name
|
||||||
|
boundType = ParseTypeName();
|
||||||
|
if (boundType.isInvalid())
|
||||||
|
invalid = true;
|
||||||
|
} else if (mayBeProtocolList) {
|
||||||
|
// If this could still be a protocol list, just capture the identifier.
|
||||||
|
// We don't want to turn it into a parameter.
|
||||||
|
protocolIdents.push_back(std::make_pair(paramName, paramLoc));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the type parameter.
|
||||||
|
DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
|
||||||
|
paramName,
|
||||||
|
paramLoc,
|
||||||
|
colonLoc,
|
||||||
|
boundType.isUsable()
|
||||||
|
? boundType.get()
|
||||||
|
: ParsedType());
|
||||||
|
if (typeParam.isUsable())
|
||||||
|
typeParams.push_back(typeParam.get());
|
||||||
|
} while (TryConsumeToken(tok::comma));
|
||||||
|
|
||||||
|
// Parse the '>'.
|
||||||
|
if (invalid) {
|
||||||
|
SkipUntil(tok::greater, tok::at, StopBeforeMatch);
|
||||||
|
if (Tok.is(tok::greater))
|
||||||
|
ConsumeToken();
|
||||||
|
} else if (ParseGreaterThanInTemplateList(rAngleLoc,
|
||||||
|
/*ConsumeLastToken=*/true,
|
||||||
|
/*ObjCGenericList=*/true)) {
|
||||||
|
Diag(lAngleLoc, diag::note_matching) << "'<'";
|
||||||
|
SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
|
||||||
|
tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
|
||||||
|
tok::comma, tok::semi },
|
||||||
|
StopBeforeMatch);
|
||||||
|
if (Tok.is(tok::greater))
|
||||||
|
ConsumeToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mayBeProtocolList) {
|
||||||
|
// A type parameter list must be followed by either a ':' (indicating the
|
||||||
|
// presence of a superclass) or a '(' (indicating that this is a category
|
||||||
|
// or extension). This disambiguates between an objc-type-parameter-list
|
||||||
|
// and a objc-protocol-refs.
|
||||||
|
if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
|
||||||
|
// Returning null indicates that we don't have a type parameter list.
|
||||||
|
// The results the caller needs to handle the protocol references are
|
||||||
|
// captured in the reference parameters already.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a type parameter list that looks like a list of protocol
|
||||||
|
// references. Turn that parameter list into type parameters.
|
||||||
|
makeProtocolIdentsIntoTypeParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form the type parameter list.
|
||||||
|
ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
|
||||||
|
getCurScope(),
|
||||||
|
lAngleLoc,
|
||||||
|
typeParams,
|
||||||
|
rAngleLoc);
|
||||||
|
|
||||||
|
// Clear out the angle locations; they're used by the caller to indicate
|
||||||
|
// whether there are any protocol references.
|
||||||
|
lAngleLoc = SourceLocation();
|
||||||
|
rAngleLoc = SourceLocation();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse an objc-type-parameter-list.
|
||||||
|
ObjCTypeParamList *Parser::parseObjCTypeParamList() {
|
||||||
|
SourceLocation lAngleLoc;
|
||||||
|
SmallVector<IdentifierLocPair, 1> protocolIdents;
|
||||||
|
SourceLocation rAngleLoc;
|
||||||
|
return parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents,
|
||||||
|
rAngleLoc,
|
||||||
|
/*mayBeProtocolList=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
/// objc-interface-decl-list:
|
/// objc-interface-decl-list:
|
||||||
/// empty
|
/// empty
|
||||||
/// objc-interface-decl-list objc-property-decl [OBJC2]
|
/// objc-interface-decl-list objc-property-decl [OBJC2]
|
||||||
|
@ -1311,7 +1534,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume the '>'.
|
// Consume the '>'.
|
||||||
if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true))
|
if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true,
|
||||||
|
/*ObjCGenericList=*/false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Convert the list of protocols identifiers into a list of protocol decls.
|
// Convert the list of protocols identifiers into a list of protocol decls.
|
||||||
|
@ -1598,6 +1822,22 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
|
||||||
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
|
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
|
||||||
Decl *ObjCImpDecl = nullptr;
|
Decl *ObjCImpDecl = nullptr;
|
||||||
|
|
||||||
|
// Neither a type parameter list nor a list of protocol references is
|
||||||
|
// permitted here. Parse and diagnose them.
|
||||||
|
if (Tok.is(tok::less)) {
|
||||||
|
SourceLocation lAngleLoc, rAngleLoc;
|
||||||
|
SmallVector<IdentifierLocPair, 8> protocolIdents;
|
||||||
|
SourceLocation diagLoc = Tok.getLocation();
|
||||||
|
if (parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents,
|
||||||
|
rAngleLoc)) {
|
||||||
|
Diag(diagLoc, diag::err_objc_parameterized_implementation)
|
||||||
|
<< SourceRange(diagLoc, PrevTokLocation);
|
||||||
|
} else if (lAngleLoc.isValid()) {
|
||||||
|
Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
|
||||||
|
<< FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Tok.is(tok::l_paren)) {
|
if (Tok.is(tok::l_paren)) {
|
||||||
// we have a category implementation.
|
// we have a category implementation.
|
||||||
ConsumeParen();
|
ConsumeParen();
|
||||||
|
|
|
@ -738,11 +738,16 @@ void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc,
|
||||||
///
|
///
|
||||||
/// \param RAngleLoc the location of the consumed '>'.
|
/// \param RAngleLoc the location of the consumed '>'.
|
||||||
///
|
///
|
||||||
/// \param ConsumeLastToken if true, the '>' is not consumed.
|
/// \param ConsumeLastToken if true, the '>' is consumed.
|
||||||
|
///
|
||||||
|
/// \param ObjCGenericList if true, this is the '>' closing an Objective-C
|
||||||
|
/// type parameter or type argument list, rather than a C++ template parameter
|
||||||
|
/// or argument list.
|
||||||
///
|
///
|
||||||
/// \returns true, if current token does not start with '>', false otherwise.
|
/// \returns true, if current token does not start with '>', false otherwise.
|
||||||
bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
||||||
bool ConsumeLastToken) {
|
bool ConsumeLastToken,
|
||||||
|
bool ObjCGenericList) {
|
||||||
// What will be left once we've consumed the '>'.
|
// What will be left once we've consumed the '>'.
|
||||||
tok::TokenKind RemainingToken;
|
tok::TokenKind RemainingToken;
|
||||||
const char *ReplacementStr = "> >";
|
const char *ReplacementStr = "> >";
|
||||||
|
@ -783,40 +788,44 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
||||||
// the token isn't '>>' or '>>>'.
|
// the token isn't '>>' or '>>>'.
|
||||||
// '>>>' is for CUDA, where this sequence of characters is parsed into
|
// '>>>' is for CUDA, where this sequence of characters is parsed into
|
||||||
// tok::greatergreatergreater, rather than two separate tokens.
|
// tok::greatergreatergreater, rather than two separate tokens.
|
||||||
|
//
|
||||||
|
// We always allow this for Objective-C type parameter and type argument
|
||||||
|
// lists.
|
||||||
RAngleLoc = Tok.getLocation();
|
RAngleLoc = Tok.getLocation();
|
||||||
|
|
||||||
// The source range of the '>>' or '>=' at the start of the token.
|
|
||||||
CharSourceRange ReplacementRange =
|
|
||||||
CharSourceRange::getCharRange(RAngleLoc,
|
|
||||||
Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(),
|
|
||||||
getLangOpts()));
|
|
||||||
|
|
||||||
// A hint to put a space between the '>>'s. In order to make the hint as
|
|
||||||
// clear as possible, we include the characters either side of the space in
|
|
||||||
// the replacement, rather than just inserting a space at SecondCharLoc.
|
|
||||||
FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
|
|
||||||
ReplacementStr);
|
|
||||||
|
|
||||||
// A hint to put another space after the token, if it would otherwise be
|
|
||||||
// lexed differently.
|
|
||||||
FixItHint Hint2;
|
|
||||||
Token Next = NextToken();
|
Token Next = NextToken();
|
||||||
if ((RemainingToken == tok::greater ||
|
if (!ObjCGenericList) {
|
||||||
RemainingToken == tok::greatergreater) &&
|
// The source range of the '>>' or '>=' at the start of the token.
|
||||||
Next.isOneOf(tok::greater, tok::greatergreater,
|
CharSourceRange ReplacementRange =
|
||||||
tok::greatergreatergreater, tok::equal, tok::greaterequal,
|
CharSourceRange::getCharRange(RAngleLoc,
|
||||||
tok::greatergreaterequal, tok::equalequal) &&
|
Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(),
|
||||||
areTokensAdjacent(Tok, Next))
|
getLangOpts()));
|
||||||
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
|
|
||||||
|
|
||||||
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
|
// A hint to put a space between the '>>'s. In order to make the hint as
|
||||||
if (getLangOpts().CPlusPlus11 &&
|
// clear as possible, we include the characters either side of the space in
|
||||||
Tok.isOneOf(tok::greatergreater, tok::greatergreatergreater))
|
// the replacement, rather than just inserting a space at SecondCharLoc.
|
||||||
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
|
FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
|
||||||
else if (Tok.is(tok::greaterequal))
|
ReplacementStr);
|
||||||
DiagId = diag::err_right_angle_bracket_equal_needs_space;
|
|
||||||
Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2;
|
// A hint to put another space after the token, if it would otherwise be
|
||||||
|
// lexed differently.
|
||||||
|
FixItHint Hint2;
|
||||||
|
if ((RemainingToken == tok::greater ||
|
||||||
|
RemainingToken == tok::greatergreater) &&
|
||||||
|
(Next.isOneOf(tok::greater, tok::greatergreater,
|
||||||
|
tok::greatergreatergreater, tok::equal,
|
||||||
|
tok::greaterequal, tok::greatergreaterequal,
|
||||||
|
tok::equalequal)) &&
|
||||||
|
areTokensAdjacent(Tok, Next))
|
||||||
|
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
|
||||||
|
|
||||||
|
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
|
||||||
|
if (getLangOpts().CPlusPlus11 &&
|
||||||
|
(Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater)))
|
||||||
|
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
|
||||||
|
else if (Tok.is(tok::greaterequal))
|
||||||
|
DiagId = diag::err_right_angle_bracket_equal_needs_space;
|
||||||
|
Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2;
|
||||||
|
}
|
||||||
|
|
||||||
// Strip the initial '>' from the token.
|
// Strip the initial '>' from the token.
|
||||||
if (RemainingToken == tok::equal && Next.is(tok::equal) &&
|
if (RemainingToken == tok::equal && Next.is(tok::equal) &&
|
||||||
|
@ -895,7 +904,8 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken);
|
return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken,
|
||||||
|
/*ObjCGenericList=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Replace the tokens that form a simple-template-id with an
|
/// \brief Replace the tokens that form a simple-template-id with an
|
||||||
|
|
|
@ -3029,7 +3029,9 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
|
||||||
|
|
||||||
case Decl::Import:
|
case Decl::Import:
|
||||||
return CXCursor_ModuleImportDecl;
|
return CXCursor_ModuleImportDecl;
|
||||||
|
|
||||||
|
case Decl::ObjCTypeParam: return CXCursor_TemplateTypeParameter;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
||||||
switch (TD->getTagKind()) {
|
switch (TD->getTagKind()) {
|
||||||
|
|
|
@ -20,12 +20,15 @@
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/AST/ExprObjC.h"
|
#include "clang/AST/ExprObjC.h"
|
||||||
#include "clang/Basic/SourceManager.h"
|
#include "clang/Basic/SourceManager.h"
|
||||||
|
#include "clang/Lex/Preprocessor.h"
|
||||||
#include "clang/Sema/DeclSpec.h"
|
#include "clang/Sema/DeclSpec.h"
|
||||||
#include "clang/Sema/ExternalSemaSource.h"
|
#include "clang/Sema/ExternalSemaSource.h"
|
||||||
#include "clang/Sema/Lookup.h"
|
#include "clang/Sema/Lookup.h"
|
||||||
#include "clang/Sema/Scope.h"
|
#include "clang/Sema/Scope.h"
|
||||||
#include "clang/Sema/ScopeInfo.h"
|
#include "clang/Sema/ScopeInfo.h"
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/DenseSet.h"
|
#include "llvm/ADT/DenseSet.h"
|
||||||
|
#include "TypeLocBuilder.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
|
@ -461,9 +464,214 @@ static void diagnoseUseOfProtocols(Sema &TheSema,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
|
||||||
|
SourceLocation paramLoc,
|
||||||
|
SourceLocation colonLoc,
|
||||||
|
ParsedType parsedTypeBound) {
|
||||||
|
// If there was an explicitly-provided type bound, check it.
|
||||||
|
TypeSourceInfo *typeBoundInfo = nullptr;
|
||||||
|
if (parsedTypeBound) {
|
||||||
|
// The type bound can be any Objective-C pointer type.
|
||||||
|
QualType typeBound = GetTypeFromParser(parsedTypeBound, &typeBoundInfo);
|
||||||
|
if (typeBound->isObjCObjectPointerType()) {
|
||||||
|
// okay
|
||||||
|
} else if (typeBound->isObjCObjectType()) {
|
||||||
|
// The user forgot the * on an Objective-C pointer type, e.g.,
|
||||||
|
// "T : NSView".
|
||||||
|
SourceLocation starLoc = PP.getLocForEndOfToken(
|
||||||
|
typeBoundInfo->getTypeLoc().getEndLoc());
|
||||||
|
Diag(typeBoundInfo->getTypeLoc().getBeginLoc(),
|
||||||
|
diag::err_objc_type_param_bound_missing_pointer)
|
||||||
|
<< typeBound << paramName
|
||||||
|
<< FixItHint::CreateInsertion(starLoc, " *");
|
||||||
|
|
||||||
|
// Create a new type location builder so we can update the type
|
||||||
|
// location information we have.
|
||||||
|
TypeLocBuilder builder;
|
||||||
|
builder.pushFullCopy(typeBoundInfo->getTypeLoc());
|
||||||
|
|
||||||
|
// Create the Objective-C pointer type.
|
||||||
|
typeBound = Context.getObjCObjectPointerType(typeBound);
|
||||||
|
ObjCObjectPointerTypeLoc newT
|
||||||
|
= builder.push<ObjCObjectPointerTypeLoc>(typeBound);
|
||||||
|
newT.setStarLoc(starLoc);
|
||||||
|
|
||||||
|
// Form the new type source information.
|
||||||
|
typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound);
|
||||||
|
} else {
|
||||||
|
// Not a
|
||||||
|
Diag(typeBoundInfo->getTypeLoc().getBeginLoc(),
|
||||||
|
diag::err_objc_type_param_bound_nonobject)
|
||||||
|
<< typeBound << paramName;
|
||||||
|
|
||||||
|
// Forget the bound; we'll default to id later.
|
||||||
|
typeBoundInfo = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there was no explicit type bound (or we removed it due to an error),
|
||||||
|
// use 'id' instead.
|
||||||
|
if (!typeBoundInfo) {
|
||||||
|
colonLoc = SourceLocation();
|
||||||
|
typeBoundInfo = Context.getTrivialTypeSourceInfo(Context.getObjCIdType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the type parameter.
|
||||||
|
return ObjCTypeParamDecl::Create(Context, CurContext, paramLoc, paramName,
|
||||||
|
colonLoc, typeBoundInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S,
|
||||||
|
SourceLocation lAngleLoc,
|
||||||
|
ArrayRef<Decl *> typeParamsIn,
|
||||||
|
SourceLocation rAngleLoc) {
|
||||||
|
// We know that the array only contains Objective-C type parameters.
|
||||||
|
ArrayRef<ObjCTypeParamDecl *>
|
||||||
|
typeParams(
|
||||||
|
reinterpret_cast<ObjCTypeParamDecl * const *>(typeParamsIn.data()),
|
||||||
|
typeParamsIn.size());
|
||||||
|
|
||||||
|
// Diagnose redeclarations of type parameters.
|
||||||
|
// We do this now because Objective-C type parameters aren't pushed into
|
||||||
|
// scope until later (after the instance variable block), but we want the
|
||||||
|
// diagnostics to occur right after we parse the type parameter list.
|
||||||
|
llvm::SmallDenseMap<IdentifierInfo *, ObjCTypeParamDecl *> knownParams;
|
||||||
|
for (auto typeParam : typeParams) {
|
||||||
|
auto known = knownParams.find(typeParam->getIdentifier());
|
||||||
|
if (known != knownParams.end()) {
|
||||||
|
Diag(typeParam->getLocation(), diag::err_objc_type_param_redecl)
|
||||||
|
<< typeParam->getIdentifier()
|
||||||
|
<< SourceRange(known->second->getLocation());
|
||||||
|
|
||||||
|
typeParam->setInvalidDecl();
|
||||||
|
} else {
|
||||||
|
knownParams.insert(std::make_pair(typeParam->getIdentifier(), typeParam));
|
||||||
|
|
||||||
|
// Push the type parameter into scope.
|
||||||
|
PushOnScopeChains(typeParam, S, /*AddToContext=*/false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the parameter list.
|
||||||
|
return ObjCTypeParamList::create(Context, lAngleLoc, typeParams, rAngleLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sema::popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList) {
|
||||||
|
for (auto typeParam : *typeParamList) {
|
||||||
|
if (!typeParam->isInvalidDecl()) {
|
||||||
|
S->RemoveDecl(typeParam);
|
||||||
|
IdResolver.RemoveDecl(typeParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/// The context in which an Objective-C type parameter list occurs, for use
|
||||||
|
/// in diagnostics.
|
||||||
|
enum class TypeParamListContext {
|
||||||
|
ForwardDeclaration,
|
||||||
|
Definition,
|
||||||
|
Category,
|
||||||
|
Extension
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check consistency between two Objective-C type parameter lists, e.g.,
|
||||||
|
/// between a category/extension and an @interface or between an @class and an
|
||||||
|
/// @interface.
|
||||||
|
static bool checkTypeParamListConsistency(Sema &S,
|
||||||
|
ObjCTypeParamList *prevTypeParams,
|
||||||
|
ObjCTypeParamList *newTypeParams,
|
||||||
|
TypeParamListContext newContext) {
|
||||||
|
// If the sizes don't match, complain about that.
|
||||||
|
if (prevTypeParams->size() != newTypeParams->size()) {
|
||||||
|
SourceLocation diagLoc;
|
||||||
|
if (newTypeParams->size() > prevTypeParams->size()) {
|
||||||
|
diagLoc = newTypeParams->begin()[prevTypeParams->size()]->getLocation();
|
||||||
|
} else {
|
||||||
|
diagLoc = S.PP.getLocForEndOfToken(newTypeParams->back()->getLocEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
S.Diag(diagLoc, diag::err_objc_type_param_arity_mismatch)
|
||||||
|
<< static_cast<unsigned>(newContext)
|
||||||
|
<< (newTypeParams->size() > prevTypeParams->size())
|
||||||
|
<< prevTypeParams->size()
|
||||||
|
<< newTypeParams->size();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match up the type parameters.
|
||||||
|
for (unsigned i = 0, n = prevTypeParams->size(); i != n; ++i) {
|
||||||
|
ObjCTypeParamDecl *prevTypeParam = prevTypeParams->begin()[i];
|
||||||
|
ObjCTypeParamDecl *newTypeParam = newTypeParams->begin()[i];
|
||||||
|
|
||||||
|
// If the bound types match, there's nothing to do.
|
||||||
|
if (S.Context.hasSameType(prevTypeParam->getUnderlyingType(),
|
||||||
|
newTypeParam->getUnderlyingType()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If the new type parameter's bound was explicit, complain about it being
|
||||||
|
// different from the original.
|
||||||
|
if (newTypeParam->hasExplicitBound()) {
|
||||||
|
SourceRange newBoundRange = newTypeParam->getTypeSourceInfo()
|
||||||
|
->getTypeLoc().getSourceRange();
|
||||||
|
S.Diag(newBoundRange.getBegin(), diag::err_objc_type_param_bound_conflict)
|
||||||
|
<< newTypeParam->getUnderlyingType()
|
||||||
|
<< newTypeParam->getDeclName()
|
||||||
|
<< prevTypeParam->hasExplicitBound()
|
||||||
|
<< prevTypeParam->getUnderlyingType()
|
||||||
|
<< (newTypeParam->getDeclName() == prevTypeParam->getDeclName())
|
||||||
|
<< prevTypeParam->getDeclName()
|
||||||
|
<< FixItHint::CreateReplacement(
|
||||||
|
newBoundRange,
|
||||||
|
prevTypeParam->getUnderlyingType().getAsString(
|
||||||
|
S.Context.getPrintingPolicy()));
|
||||||
|
|
||||||
|
S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here)
|
||||||
|
<< prevTypeParam->getDeclName();
|
||||||
|
|
||||||
|
// Override the new type parameter's bound type with the previous type,
|
||||||
|
// so that it's consistent.
|
||||||
|
newTypeParam->setTypeSourceInfo(
|
||||||
|
S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The new type parameter got the implicit bound of 'id'. That's okay for
|
||||||
|
// categories and extensions (overwrite it later), but not for forward
|
||||||
|
// declarations and @interfaces, because those must be standalone.
|
||||||
|
if (newContext == TypeParamListContext::ForwardDeclaration ||
|
||||||
|
newContext == TypeParamListContext::Definition) {
|
||||||
|
// Diagnose this problem for forward declarations and definitions.
|
||||||
|
SourceLocation insertionLoc
|
||||||
|
= S.PP.getLocForEndOfToken(newTypeParam->getLocation());
|
||||||
|
std::string newCode
|
||||||
|
= " : " + prevTypeParam->getUnderlyingType().getAsString(
|
||||||
|
S.Context.getPrintingPolicy());
|
||||||
|
S.Diag(newTypeParam->getLocation(),
|
||||||
|
diag::err_objc_type_param_bound_missing)
|
||||||
|
<< prevTypeParam->getUnderlyingType()
|
||||||
|
<< newTypeParam->getDeclName()
|
||||||
|
<< (newContext == TypeParamListContext::ForwardDeclaration)
|
||||||
|
<< FixItHint::CreateInsertion(insertionLoc, newCode);
|
||||||
|
|
||||||
|
S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here)
|
||||||
|
<< prevTypeParam->getDeclName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the new type parameter's bound to match the previous one.
|
||||||
|
newTypeParam->setTypeSourceInfo(
|
||||||
|
S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Decl *Sema::
|
Decl *Sema::
|
||||||
ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
||||||
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
IdentifierInfo *SuperName, SourceLocation SuperLoc,
|
IdentifierInfo *SuperName, SourceLocation SuperLoc,
|
||||||
Decl * const *ProtoRefs, unsigned NumProtoRefs,
|
Decl * const *ProtoRefs, unsigned NumProtoRefs,
|
||||||
const SourceLocation *ProtoLocs,
|
const SourceLocation *ProtoLocs,
|
||||||
|
@ -498,10 +706,47 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
||||||
ClassName = PrevIDecl->getIdentifier();
|
ClassName = PrevIDecl->getIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there was a forward declaration with type parameters, check
|
||||||
|
// for consistency.
|
||||||
|
if (PrevIDecl) {
|
||||||
|
if (ObjCTypeParamList *prevTypeParamList = PrevIDecl->getTypeParamList()) {
|
||||||
|
if (typeParamList) {
|
||||||
|
// Both have type parameter lists; check for consistency.
|
||||||
|
if (checkTypeParamListConsistency(*this, prevTypeParamList,
|
||||||
|
typeParamList,
|
||||||
|
TypeParamListContext::Definition)) {
|
||||||
|
typeParamList = nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Diag(ClassLoc, diag::err_objc_parameterized_forward_class_first)
|
||||||
|
<< ClassName;
|
||||||
|
Diag(prevTypeParamList->getLAngleLoc(), diag::note_previous_decl)
|
||||||
|
<< ClassName;
|
||||||
|
|
||||||
|
// Clone the type parameter list.
|
||||||
|
SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams;
|
||||||
|
for (auto typeParam : *prevTypeParamList) {
|
||||||
|
clonedTypeParams.push_back(
|
||||||
|
ObjCTypeParamDecl::Create(
|
||||||
|
Context,
|
||||||
|
CurContext,
|
||||||
|
SourceLocation(),
|
||||||
|
typeParam->getIdentifier(),
|
||||||
|
SourceLocation(),
|
||||||
|
Context.getTrivialTypeSourceInfo(typeParam->getUnderlyingType())));
|
||||||
|
}
|
||||||
|
|
||||||
|
typeParamList = ObjCTypeParamList::create(Context,
|
||||||
|
SourceLocation(),
|
||||||
|
clonedTypeParams,
|
||||||
|
SourceLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ObjCInterfaceDecl *IDecl
|
ObjCInterfaceDecl *IDecl
|
||||||
= ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
|
= ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
|
||||||
PrevIDecl, ClassLoc);
|
typeParamList, PrevIDecl, ClassLoc);
|
||||||
|
|
||||||
if (PrevIDecl) {
|
if (PrevIDecl) {
|
||||||
// Class already seen. Was it a definition?
|
// Class already seen. Was it a definition?
|
||||||
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
|
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
|
||||||
|
@ -906,6 +1151,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
|
||||||
Decl *Sema::
|
Decl *Sema::
|
||||||
ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
||||||
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
||||||
|
ObjCTypeParamList *typeParamList,
|
||||||
IdentifierInfo *CategoryName,
|
IdentifierInfo *CategoryName,
|
||||||
SourceLocation CategoryLoc,
|
SourceLocation CategoryLoc,
|
||||||
Decl * const *ProtoRefs,
|
Decl * const *ProtoRefs,
|
||||||
|
@ -925,7 +1171,8 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
||||||
// the enclosing method declarations. We mark the decl invalid
|
// the enclosing method declarations. We mark the decl invalid
|
||||||
// to make it clear that this isn't a valid AST.
|
// to make it clear that this isn't a valid AST.
|
||||||
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
|
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
|
||||||
ClassLoc, CategoryLoc, CategoryName,IDecl);
|
ClassLoc, CategoryLoc, CategoryName,
|
||||||
|
IDecl, typeParamList);
|
||||||
CDecl->setInvalidDecl();
|
CDecl->setInvalidDecl();
|
||||||
CurContext->addDecl(CDecl);
|
CurContext->addDecl(CDecl);
|
||||||
|
|
||||||
|
@ -951,8 +1198,28 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have a type parameter list, check it.
|
||||||
|
if (typeParamList) {
|
||||||
|
if (auto prevTypeParamList = IDecl->getTypeParamList()) {
|
||||||
|
if (checkTypeParamListConsistency(*this, prevTypeParamList, typeParamList,
|
||||||
|
CategoryName
|
||||||
|
? TypeParamListContext::Category
|
||||||
|
: TypeParamListContext::Extension))
|
||||||
|
typeParamList = nullptr;
|
||||||
|
} else {
|
||||||
|
Diag(typeParamList->getLAngleLoc(),
|
||||||
|
diag::err_objc_parameterized_category_nonclass)
|
||||||
|
<< (CategoryName != nullptr)
|
||||||
|
<< ClassName
|
||||||
|
<< typeParamList->getSourceRange();
|
||||||
|
|
||||||
|
typeParamList = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
|
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
|
||||||
ClassLoc, CategoryLoc, CategoryName, IDecl);
|
ClassLoc, CategoryLoc, CategoryName, IDecl,
|
||||||
|
typeParamList);
|
||||||
// FIXME: PushOnScopeChains?
|
// FIXME: PushOnScopeChains?
|
||||||
CurContext->addDecl(CDecl);
|
CurContext->addDecl(CDecl);
|
||||||
|
|
||||||
|
@ -987,7 +1254,8 @@ Decl *Sema::ActOnStartCategoryImplementation(
|
||||||
// Create and install one.
|
// Create and install one.
|
||||||
CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, AtCatImplLoc,
|
CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, AtCatImplLoc,
|
||||||
ClassLoc, CatLoc,
|
ClassLoc, CatLoc,
|
||||||
CatName, IDecl);
|
CatName, IDecl,
|
||||||
|
/*typeParamList=*/nullptr);
|
||||||
CatIDecl->setImplicit();
|
CatIDecl->setImplicit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1101,7 +1369,8 @@ Decl *Sema::ActOnStartClassImplementation(
|
||||||
// FIXME: Do we support attributes on the @implementation? If so we should
|
// FIXME: Do we support attributes on the @implementation? If so we should
|
||||||
// copy them over.
|
// copy them over.
|
||||||
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
|
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
|
||||||
ClassName, /*PrevDecl=*/nullptr, ClassLoc,
|
ClassName, /*typeParamList=*/nullptr,
|
||||||
|
/*PrevDecl=*/nullptr, ClassLoc,
|
||||||
true);
|
true);
|
||||||
IDecl->startDefinition();
|
IDecl->startDefinition();
|
||||||
if (SDecl) {
|
if (SDecl) {
|
||||||
|
@ -2083,6 +2352,7 @@ Sema::DeclGroupPtrTy
|
||||||
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
||||||
IdentifierInfo **IdentList,
|
IdentifierInfo **IdentList,
|
||||||
SourceLocation *IdentLocs,
|
SourceLocation *IdentLocs,
|
||||||
|
ArrayRef<ObjCTypeParamList *> TypeParamLists,
|
||||||
unsigned NumElts) {
|
unsigned NumElts) {
|
||||||
SmallVector<Decl *, 8> DeclsInGroup;
|
SmallVector<Decl *, 8> DeclsInGroup;
|
||||||
for (unsigned i = 0; i != NumElts; ++i) {
|
for (unsigned i = 0; i != NumElts; ++i) {
|
||||||
|
@ -2137,9 +2407,33 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
||||||
ClassName = PrevIDecl->getIdentifier();
|
ClassName = PrevIDecl->getIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this forward declaration has type parameters, compare them with the
|
||||||
|
// type parameters of the previous declaration.
|
||||||
|
ObjCTypeParamList *TypeParams = TypeParamLists[i];
|
||||||
|
if (PrevIDecl && TypeParams) {
|
||||||
|
if (ObjCTypeParamList *PrevTypeParams = PrevIDecl->getTypeParamList()) {
|
||||||
|
// Check for consistency with the previous declaration.
|
||||||
|
if (checkTypeParamListConsistency(
|
||||||
|
*this, PrevTypeParams, TypeParams,
|
||||||
|
TypeParamListContext::ForwardDeclaration)) {
|
||||||
|
TypeParams = nullptr;
|
||||||
|
}
|
||||||
|
} else if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
|
||||||
|
// The @interface does not have type parameters. Complain.
|
||||||
|
Diag(IdentLocs[i], diag::err_objc_parameterized_forward_class)
|
||||||
|
<< ClassName
|
||||||
|
<< TypeParams->getSourceRange();
|
||||||
|
Diag(Def->getLocation(), diag::note_defined_here)
|
||||||
|
<< ClassName;
|
||||||
|
|
||||||
|
TypeParams = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ObjCInterfaceDecl *IDecl
|
ObjCInterfaceDecl *IDecl
|
||||||
= ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
|
= ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
|
||||||
ClassName, PrevIDecl, IdentLocs[i]);
|
ClassName, TypeParams, PrevIDecl,
|
||||||
|
IdentLocs[i]);
|
||||||
IDecl->setAtEndRange(IdentLocs[i]);
|
IDecl->setAtEndRange(IdentLocs[i]);
|
||||||
|
|
||||||
PushOnScopeChains(IDecl, TUScope);
|
PushOnScopeChains(IDecl, TUScope);
|
||||||
|
|
|
@ -133,7 +133,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
|
||||||
ObjCInterfaceDecl::Create (Context,
|
ObjCInterfaceDecl::Create (Context,
|
||||||
Context.getTranslationUnitDecl(),
|
Context.getTranslationUnitDecl(),
|
||||||
SourceLocation(), NSIdent,
|
SourceLocation(), NSIdent,
|
||||||
nullptr, SourceLocation());
|
nullptr, nullptr, SourceLocation());
|
||||||
Ty = Context.getObjCInterfaceType(NSStringIDecl);
|
Ty = Context.getObjCInterfaceType(NSStringIDecl);
|
||||||
Context.setObjCNSStringType(Ty);
|
Context.setObjCNSStringType(Ty);
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,8 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
|
||||||
S.NSNumberDecl = ObjCInterfaceDecl::Create(CX,
|
S.NSNumberDecl = ObjCInterfaceDecl::Create(CX,
|
||||||
CX.getTranslationUnitDecl(),
|
CX.getTranslationUnitDecl(),
|
||||||
SourceLocation(), NSNumberId,
|
SourceLocation(), NSNumberId,
|
||||||
nullptr, SourceLocation());
|
nullptr, nullptr,
|
||||||
|
SourceLocation());
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, require a declaration of NSNumber.
|
// Otherwise, require a declaration of NSNumber.
|
||||||
S.Diag(Loc, diag::err_undeclared_nsnumber);
|
S.Diag(Loc, diag::err_undeclared_nsnumber);
|
||||||
|
@ -475,7 +476,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
|
||||||
NSStringDecl = ObjCInterfaceDecl::Create(Context, TU,
|
NSStringDecl = ObjCInterfaceDecl::Create(Context, TU,
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
NSStringId,
|
NSStringId,
|
||||||
nullptr, SourceLocation());
|
nullptr, nullptr,
|
||||||
|
SourceLocation());
|
||||||
} else {
|
} else {
|
||||||
Diag(SR.getBegin(), diag::err_undeclared_nsstring);
|
Diag(SR.getBegin(), diag::err_undeclared_nsstring);
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
@ -591,7 +593,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
|
||||||
DeclContext *TU = Context.getTranslationUnitDecl();
|
DeclContext *TU = Context.getTranslationUnitDecl();
|
||||||
NSValueDecl = ObjCInterfaceDecl::Create(Context, TU,
|
NSValueDecl = ObjCInterfaceDecl::Create(Context, TU,
|
||||||
SourceLocation(), NSValueId,
|
SourceLocation(), NSValueId,
|
||||||
nullptr, SourceLocation());
|
nullptr, nullptr,
|
||||||
|
SourceLocation());
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, require a declaration of NSValue.
|
// Otherwise, require a declaration of NSValue.
|
||||||
Diag(SR.getBegin(), diag::err_undeclared_nsvalue);
|
Diag(SR.getBegin(), diag::err_undeclared_nsvalue);
|
||||||
|
@ -755,7 +758,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
|
||||||
Context.getTranslationUnitDecl(),
|
Context.getTranslationUnitDecl(),
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
|
NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
|
||||||
nullptr, SourceLocation());
|
nullptr, nullptr, SourceLocation());
|
||||||
|
|
||||||
if (!NSArrayDecl) {
|
if (!NSArrayDecl) {
|
||||||
Diag(SR.getBegin(), diag::err_undeclared_nsarray);
|
Diag(SR.getBegin(), diag::err_undeclared_nsarray);
|
||||||
|
@ -870,7 +873,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
|
||||||
Context.getTranslationUnitDecl(),
|
Context.getTranslationUnitDecl(),
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
|
NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
|
||||||
nullptr, SourceLocation());
|
nullptr, nullptr, SourceLocation());
|
||||||
|
|
||||||
if (!NSDictionaryDecl) {
|
if (!NSDictionaryDecl) {
|
||||||
Diag(SR.getBegin(), diag::err_undeclared_nsdictionary);
|
Diag(SR.getBegin(), diag::err_undeclared_nsdictionary);
|
||||||
|
|
|
@ -221,6 +221,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
|
||||||
// redeclarable.
|
// redeclarable.
|
||||||
case Decl::ImplicitParam:
|
case Decl::ImplicitParam:
|
||||||
case Decl::ParmVar:
|
case Decl::ParmVar:
|
||||||
|
case Decl::ObjCTypeParam:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -350,8 +350,11 @@ namespace clang {
|
||||||
RedeclarableTemplateDecl *Existing,
|
RedeclarableTemplateDecl *Existing,
|
||||||
DeclID DsID);
|
DeclID DsID);
|
||||||
|
|
||||||
|
ObjCTypeParamList *ReadObjCTypeParamList();
|
||||||
|
|
||||||
// FIXME: Reorder according to DeclNodes.td?
|
// FIXME: Reorder according to DeclNodes.td?
|
||||||
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
||||||
|
void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
|
||||||
void VisitObjCContainerDecl(ObjCContainerDecl *D);
|
void VisitObjCContainerDecl(ObjCContainerDecl *D);
|
||||||
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
||||||
void VisitObjCIvarDecl(ObjCIvarDecl *D);
|
void VisitObjCIvarDecl(ObjCIvarDecl *D);
|
||||||
|
@ -899,18 +902,46 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
|
||||||
MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs);
|
MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
|
||||||
|
VisitTypedefNameDecl(D);
|
||||||
|
D->ColonLoc = ReadSourceLocation(Record, Idx);
|
||||||
|
}
|
||||||
|
|
||||||
void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
|
void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
|
||||||
VisitNamedDecl(CD);
|
VisitNamedDecl(CD);
|
||||||
CD->setAtStartLoc(ReadSourceLocation(Record, Idx));
|
CD->setAtStartLoc(ReadSourceLocation(Record, Idx));
|
||||||
CD->setAtEndRange(ReadSourceRange(Record, Idx));
|
CD->setAtEndRange(ReadSourceRange(Record, Idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() {
|
||||||
|
unsigned numParams = Record[Idx++];
|
||||||
|
if (numParams == 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
SmallVector<ObjCTypeParamDecl *, 4> typeParams;
|
||||||
|
typeParams.reserve(numParams);
|
||||||
|
for (unsigned i = 0; i != numParams; ++i) {
|
||||||
|
auto typeParam = ReadDeclAs<ObjCTypeParamDecl>(Record, Idx);
|
||||||
|
if (!typeParam)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
typeParams.push_back(typeParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLocation lAngleLoc = ReadSourceLocation(Record, Idx);
|
||||||
|
SourceLocation rAngleLoc = ReadSourceLocation(Record, Idx);
|
||||||
|
|
||||||
|
return ObjCTypeParamList::create(Reader.getContext(), lAngleLoc,
|
||||||
|
typeParams, rAngleLoc);
|
||||||
|
}
|
||||||
|
|
||||||
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
|
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
|
||||||
RedeclarableResult Redecl = VisitRedeclarable(ID);
|
RedeclarableResult Redecl = VisitRedeclarable(ID);
|
||||||
VisitObjCContainerDecl(ID);
|
VisitObjCContainerDecl(ID);
|
||||||
TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
|
TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
|
||||||
mergeRedeclarable(ID, Redecl);
|
mergeRedeclarable(ID, Redecl);
|
||||||
|
|
||||||
|
ID->TypeParamList = ReadObjCTypeParamList();
|
||||||
if (Record[Idx++]) {
|
if (Record[Idx++]) {
|
||||||
// Read the definition.
|
// Read the definition.
|
||||||
ID->allocateDefinitionData();
|
ID->allocateDefinitionData();
|
||||||
|
@ -1020,6 +1051,7 @@ void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
|
||||||
Reader.CategoriesDeserialized.insert(CD);
|
Reader.CategoriesDeserialized.insert(CD);
|
||||||
|
|
||||||
CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
|
CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
|
||||||
|
CD->TypeParamList = ReadObjCTypeParamList();
|
||||||
unsigned NumProtoRefs = Record[Idx++];
|
unsigned NumProtoRefs = Record[Idx++];
|
||||||
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
|
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
|
||||||
ProtoRefs.reserve(NumProtoRefs);
|
ProtoRefs.reserve(NumProtoRefs);
|
||||||
|
@ -3259,6 +3291,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
||||||
case DECL_EMPTY:
|
case DECL_EMPTY:
|
||||||
D = EmptyDecl::CreateDeserialized(Context, ID);
|
D = EmptyDecl::CreateDeserialized(Context, ID);
|
||||||
break;
|
break;
|
||||||
|
case DECL_OBJC_TYPE_PARAM:
|
||||||
|
D = ObjCTypeParamDecl::CreateDeserialized(Context, ID);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(D && "Unknown declaration reading AST file");
|
assert(D && "Unknown declaration reading AST file");
|
||||||
|
|
|
@ -117,6 +117,7 @@ namespace clang {
|
||||||
|
|
||||||
// FIXME: Put in the same order is DeclNodes.td?
|
// FIXME: Put in the same order is DeclNodes.td?
|
||||||
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
||||||
|
void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
|
||||||
void VisitObjCContainerDecl(ObjCContainerDecl *D);
|
void VisitObjCContainerDecl(ObjCContainerDecl *D);
|
||||||
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
||||||
void VisitObjCIvarDecl(ObjCIvarDecl *D);
|
void VisitObjCIvarDecl(ObjCIvarDecl *D);
|
||||||
|
@ -131,6 +132,22 @@ namespace clang {
|
||||||
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
|
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
|
||||||
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
|
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
|
||||||
|
|
||||||
|
/// Add an Objective-C type parameter list to the given record.
|
||||||
|
void AddObjCTypeParamList(ObjCTypeParamList *typeParams) {
|
||||||
|
// Empty type parameter list.
|
||||||
|
if (!typeParams) {
|
||||||
|
Record.push_back(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Record.push_back(typeParams->size());
|
||||||
|
for (auto typeParam : *typeParams) {
|
||||||
|
Writer.AddDeclRef(typeParam, Record);
|
||||||
|
}
|
||||||
|
Writer.AddSourceLocation(typeParams->getLAngleLoc(), Record);
|
||||||
|
Writer.AddSourceLocation(typeParams->getRAngleLoc(), Record);
|
||||||
|
}
|
||||||
|
|
||||||
void AddFunctionDefinition(const FunctionDecl *FD) {
|
void AddFunctionDefinition(const FunctionDecl *FD) {
|
||||||
assert(FD->doesThisDeclarationHaveABody());
|
assert(FD->doesThisDeclarationHaveABody());
|
||||||
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
|
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
|
||||||
|
@ -562,6 +579,13 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
|
||||||
Code = serialization::DECL_OBJC_METHOD;
|
Code = serialization::DECL_OBJC_METHOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
|
||||||
|
VisitTypedefNameDecl(D);
|
||||||
|
Writer.AddSourceLocation(D->ColonLoc, Record);
|
||||||
|
|
||||||
|
Code = serialization::DECL_OBJC_TYPE_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
|
void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
|
||||||
VisitNamedDecl(D);
|
VisitNamedDecl(D);
|
||||||
Writer.AddSourceLocation(D->getAtStartLoc(), Record);
|
Writer.AddSourceLocation(D->getAtStartLoc(), Record);
|
||||||
|
@ -573,6 +597,7 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
||||||
VisitRedeclarable(D);
|
VisitRedeclarable(D);
|
||||||
VisitObjCContainerDecl(D);
|
VisitObjCContainerDecl(D);
|
||||||
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
|
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
|
||||||
|
AddObjCTypeParamList(D->TypeParamList);
|
||||||
|
|
||||||
Record.push_back(D->isThisDeclarationADefinition());
|
Record.push_back(D->isThisDeclarationADefinition());
|
||||||
if (D->isThisDeclarationADefinition()) {
|
if (D->isThisDeclarationADefinition()) {
|
||||||
|
@ -660,6 +685,7 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
||||||
Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
|
Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
|
||||||
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
|
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
|
||||||
Writer.AddDeclRef(D->getClassInterface(), Record);
|
Writer.AddDeclRef(D->getClassInterface(), Record);
|
||||||
|
AddObjCTypeParamList(D->TypeParamList);
|
||||||
Record.push_back(D->protocol_size());
|
Record.push_back(D->protocol_size());
|
||||||
for (const auto *I : D->protocols())
|
for (const auto *I : D->protocols())
|
||||||
Writer.AddDeclRef(I, Record);
|
Writer.AddDeclRef(I, Record);
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
// RUN: rm -rf %t
|
||||||
|
// RUN: mkdir %t
|
||||||
|
// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %s > %t/out
|
||||||
|
// RUN: FileCheck %s < %t/out
|
||||||
|
|
||||||
|
// Ensure that XML we generate is not invalid.
|
||||||
|
// RUN: FileCheck %s -check-prefix=WRONG < %t/out
|
||||||
|
// WRONG-NOT: CommentXMLInvalid
|
||||||
|
|
||||||
|
@protocol NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
// CHECK: <Declaration>@interface A <T : id, U : NSObject *> : NSObject
|
||||||
|
/// A
|
||||||
|
@interface A<T : id, U : NSObject *> : NSObject
|
||||||
|
@end
|
|
@ -0,0 +1,30 @@
|
||||||
|
// RUN: %clang_cc1 -emit-pch %s -o %t
|
||||||
|
// RUN: %clang_cc1 -include-pch %t -verify %s
|
||||||
|
|
||||||
|
#ifndef HEADER_INCLUDED
|
||||||
|
|
||||||
|
#define HEADER_INCLUDED
|
||||||
|
|
||||||
|
@protocol NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_root_class))
|
||||||
|
@interface NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface PC1<T, U : NSObject *> : NSObject
|
||||||
|
// expected-note@-2{{type parameter 'U' declared here}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface PC1<T, U : NSObject *> (Cat1)
|
||||||
|
@end
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
@interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id}}
|
||||||
|
// expected-note@15{{type parameter 'T' declared here}}
|
||||||
|
U : id> (Cat2) // expected-error{{type bound 'id' for type parameter 'U' conflicts with previous bound 'NSObject *'}}
|
||||||
|
// expected-note@15{{type parameter 'U' declared here}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
@interface K @end
|
@interface K @end
|
||||||
|
|
||||||
@implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}}
|
@implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}} expected-note{{to match this '<'}}
|
||||||
@end // expected-error {{expected '>'}}
|
@end // expected-error {{expected '>'}}
|
||||||
|
|
||||||
// rdar://13920026
|
// rdar://13920026
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
// RUN: %clang_cc1 %s -verify
|
||||||
|
|
||||||
|
@protocol NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_root_class))
|
||||||
|
@interface NSObject <NSObject> // expected-note{{'NSObject' defined here}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSString : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Parsing parameterized classes.
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Parse type parameters with a bound
|
||||||
|
@interface PC1<T, U : NSObject*> : NSObject
|
||||||
|
// expected-note@-1{{type parameter 'T' declared here}}
|
||||||
|
// expected-note@-2{{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 '> >')}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Parse multiple type parameters.
|
||||||
|
@interface PC3<T, U : id> : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Parse multiple type parameters--grammatically ambiguous with protocol refs.
|
||||||
|
@interface PC4<T, U, V> : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Parse a type parameter list without a superclass.
|
||||||
|
@interface PC5<T : id> // expected-error{{parameterized Objective-C class 'PC5' must have a superclass}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Parse a type parameter with name conflicts.
|
||||||
|
@interface PC6<T, U,
|
||||||
|
T> : NSObject // expected-error{{redeclaration of type parameter 'T'}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Parse Objective-C protocol references.
|
||||||
|
@interface PC7<T> // expected-error{{cannot find protocol declaration for 'T'}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Parse both type parameters and protocol references.
|
||||||
|
@interface PC8<T> : NSObject <NSObject>
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Type parameters with improper bounds.
|
||||||
|
@interface PC9<T : int, // expected-error{{type bound 'int' for type parameter 'T' is not an Objective-C pointer type}}
|
||||||
|
U : NSString> : NSObject // expected-error{{missing '*' in type bound 'NSString' for type parameter 'U'}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Parsing parameterized forward declarations classes.
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Okay: forward declaration without type parameters.
|
||||||
|
@class PC10;
|
||||||
|
|
||||||
|
// Okay: forward declarations with type parameters.
|
||||||
|
@class PC10<T, U : NSObject *>, PC11<T : NSObject *, U : id>; // expected-note{{type parameter 'T' declared here}}
|
||||||
|
|
||||||
|
// Okay: forward declaration without type parameters following ones
|
||||||
|
// with type parameters.
|
||||||
|
@class PC10, PC11;
|
||||||
|
|
||||||
|
// Okay: definition of class with type parameters that was formerly
|
||||||
|
// declared with the same type parameters.
|
||||||
|
@interface PC10<T, U : NSObject *> : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Mismatched parameters in declaration of @interface following @class.
|
||||||
|
@interface PC11<T, U> : NSObject // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @interface}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface PC12<T : NSObject *> : NSObject // expected-note{{type parameter 'T' declared here}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@class PC12;
|
||||||
|
|
||||||
|
// Mismatched parameters in subsequent forward declarations.
|
||||||
|
@class PC13<T : NSObject *>; // expected-note{{type parameter 'T' declared here}}
|
||||||
|
@class PC13;
|
||||||
|
@class PC13<U>; // expected-error{{missing type bound 'NSObject *' for type parameter 'U' in @class}}
|
||||||
|
|
||||||
|
// Mismatch parameters in declaration of @class following @interface.
|
||||||
|
@class PC12<T>; // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @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}}
|
||||||
|
|
||||||
|
// Parameterized forward declaration preceding the definition (that is
|
||||||
|
// not parameterized).
|
||||||
|
@class NSNumber<T : NSObject *>; // expected-note{{'NSNumber' declared here}}
|
||||||
|
@interface NSNumber : NSObject // expected-error{{class 'NSNumber' previously declared with type parameters}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@class PC14;
|
||||||
|
|
||||||
|
// Okay: definition of class with type parameters that was formerly
|
||||||
|
// declared without type parameters.
|
||||||
|
@interface PC14<T, U : NSObject *> : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Parsing parameterized categories and extensions.
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Inferring type bounds
|
||||||
|
@interface PC1<T, U> (Cat1) <NSObject>
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Matching type bounds
|
||||||
|
@interface PC1<T : id, U : NSObject *> (Cat2) <NSObject>
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Inferring type bounds
|
||||||
|
@interface PC1<T, U> () <NSObject>
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Matching type bounds
|
||||||
|
@interface PC1<T : id, U : NSObject *> () <NSObject>
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Missing type parameters.
|
||||||
|
@interface PC1<T> () // expected-error{{extension has too few type parameters (expected 2, have 1)}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Extra type parameters.
|
||||||
|
@interface PC1<T, U, V> (Cat3) // expected-error{{category has too many type parameters (expected 2, have 3)}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Mismatched bounds.
|
||||||
|
@interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id'}}
|
||||||
|
X : id> () // expected-error{{type bound 'id' for type parameter 'X' conflicts with previous bound 'NSObject *'for type parameter 'U'}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Parameterized category/extension of non-parameterized class.
|
||||||
|
@interface NSObject<T> (Cat1) // expected-error{{category of non-parameterized class 'NSObject' cannot have type parameters}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSObject<T> () // expected-error{{extension of non-parameterized class 'NSObject' cannot have type parameters}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// @implementations cannot have type parameters
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
@implementation PC1<T : id> // expected-error{{@implementation cannot have type parameters}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation PC2<T> // expected-error{{@implementation declaration cannot be protocol qualified}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation PC1<T> (Cat1) // expected-error{{@implementation cannot have type parameters}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation PC1<T : id> (Cat2) // expected-error{{@implementation cannot have type parameters}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Interfaces involving type parameters
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
@interface PC20<T : id, U : NSObject *, V : NSString *> : NSObject {
|
||||||
|
T object;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (U)method:(V)param; // expected-note{{passing argument to parameter 'param' here}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface PC20<T, U, V> (Cat1)
|
||||||
|
- (U)catMethod:(V)param; // expected-note{{passing argument to parameter 'param' here}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface PC20<X, Y, Z>()
|
||||||
|
- (X)extMethod:(Y)param; // expected-note{{passing argument to parameter 'param' here}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
void test_PC20_unspecialized(PC20 *pc20) {
|
||||||
|
// FIXME: replace type parameters with underlying types?
|
||||||
|
int *ip = [pc20 method: 0]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'U' (aka 'NSObject *')}}
|
||||||
|
[pc20 method: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
|
||||||
|
|
||||||
|
ip = [pc20 catMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'U' (aka 'NSObject *')}}
|
||||||
|
[pc20 catMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
|
||||||
|
|
||||||
|
ip = [pc20 extMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'X' (aka 'id')}}
|
||||||
|
[pc20 extMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'Y' (aka 'NSObject *')}}
|
||||||
|
}
|
|
@ -5038,6 +5038,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
|
||||||
case Decl::ClassScopeFunctionSpecialization:
|
case Decl::ClassScopeFunctionSpecialization:
|
||||||
case Decl::Import:
|
case Decl::Import:
|
||||||
case Decl::OMPThreadPrivate:
|
case Decl::OMPThreadPrivate:
|
||||||
|
case Decl::ObjCTypeParam:
|
||||||
return C;
|
return C;
|
||||||
|
|
||||||
// Declaration kinds that don't make any sense here, but are
|
// Declaration kinds that don't make any sense here, but are
|
||||||
|
@ -6321,6 +6322,7 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
|
||||||
case Decl::ObjCProperty:
|
case Decl::ObjCProperty:
|
||||||
case Decl::ObjCPropertyImpl:
|
case Decl::ObjCPropertyImpl:
|
||||||
case Decl::ObjCProtocol:
|
case Decl::ObjCProtocol:
|
||||||
|
case Decl::ObjCTypeParam:
|
||||||
return CXLanguage_ObjC;
|
return CXLanguage_ObjC;
|
||||||
case Decl::CXXConstructor:
|
case Decl::CXXConstructor:
|
||||||
case Decl::CXXConversion:
|
case Decl::CXXConversion:
|
||||||
|
|
Loading…
Reference in New Issue