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:
Douglas Gregor 2015-07-07 03:57:15 +00:00
parent 27cac9536c
commit 5df68d34cd
30 changed files with 1424 additions and 91 deletions

View File

@ -1307,7 +1307,12 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// 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
})
@ -1316,7 +1321,12 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// 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
})
@ -1335,6 +1345,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
return true;
})
DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
if (D->hasExplicitBound()) {
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
// We shouldn't traverse D->getTypeForDecl(); it's a result of
// declaring the type alias, not something that was written in the
// source.
}
})
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
if (D->getTypeSourceInfo())
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));

View File

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

View File

@ -1382,7 +1382,11 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// 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
})
@ -1391,7 +1395,11 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// 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
})
@ -1410,6 +1418,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
return true;
})
DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
if (D->hasExplicitBound()) {
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
// We shouldn't traverse D->getTypeForDecl(); it's a result of
// declaring the type alias, not something that was written in the
// source.
}
})
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
if (D->getTypeSourceInfo())
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));

View File

@ -21,6 +21,7 @@ def Named : Decl<1>;
def TypedefName : DDecl<Type, 1>;
def Typedef : DDecl<TypedefName>;
def TypeAlias : DDecl<TypedefName>;
def ObjCTypeParam : DDecl<TypedefName>;
def UnresolvedUsingTypename : DDecl<Type>;
def Tag : DDecl<Type, 1>, DeclContext;
def Enum : DDecl<Tag>;

View File

@ -1017,4 +1017,17 @@ def err_module_expected_semi : Error<
"expected ';' after module name">;
}
let CategoryName = "Generics Issue" in {
def err_objc_expected_type_parameter : Error<
"expected type parameter name">;
def err_objc_parameterized_class_without_base : Error<
"parameterized Objective-C class %0 must have a superclass">;
def err_objc_parameterized_implementation : Error<
"@implementation cannot have type parameters">;
}
} // end of Parser diagnostics

View File

@ -7743,6 +7743,42 @@ def warn_nullability_missing : Warning<
"%select{pointer|block pointer|member pointer}0 is missing a nullability "
"type specifier (_Nonnull, _Nullable, or _Null_unspecified)">,
InGroup<NullabilityCompleteness>;
}
let CategoryName = "Generics Issue" in {
def err_objc_type_param_bound_nonobject : Error<
"type bound %0 for type parameter %1 is not an Objective-C pointer type">;
def err_objc_type_param_bound_missing_pointer : Error<
"missing '*' in type bound %0 for type parameter %1">;
def err_objc_type_param_redecl : Error<
"redeclaration of type parameter %0">;
def err_objc_type_param_arity_mismatch : Error<
"%select{forward class declaration|class definition|category|extension}0 has "
"too %select{few|many}1 type parameters (expected %2, have %3)">;
def err_objc_type_param_bound_conflict : Error<
"type bound %0 for type parameter %1 conflicts with "
"%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">;
def note_objc_type_param_here : Note<"type parameter %0 declared here">;
def err_objc_type_param_bound_missing : Error<
"missing type bound %0 for type parameter %1 in %select{@interface|@class}2">;
def err_objc_parameterized_category_nonclass : Error<
"%select{extension|category}0 of non-parameterized class %1 cannot have type "
"parameters">;
def err_objc_parameterized_forward_class : Error<
"forward declaration of non-parameterized class %0 cannot have type "
"parameters">;
def err_objc_parameterized_forward_class_first : Error<
"class %0 previously declared with type parameters">;
}

View File

@ -46,6 +46,8 @@ namespace clang {
class PoisonSEHIdentifiersRAIIObject;
class VersionTuple;
class OMPClause;
class ObjCTypeParamList;
class ObjCTypeParameter;
/// Parser - This implements a parser for the C family of languages. After
/// parsing units of the grammar, productions are invoked to handle whatever has
@ -1246,6 +1248,13 @@ private:
DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParsedAttributes &prefixAttrs);
ObjCTypeParamList *parseObjCTypeParamList();
ObjCTypeParamList *parseObjCTypeParamListOrProtocolRefs(
SourceLocation &lAngleLoc,
SmallVectorImpl<IdentifierLocPair> &protocolIdents,
SourceLocation &rAngleLoc,
bool mayBeProtocolList = true);
void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
BalancedDelimiterTracker &T,
SmallVectorImpl<Decl *> &AllIvarDecls,
@ -2469,7 +2478,8 @@ private:
typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
bool ConsumeLastToken);
bool ConsumeLastToken,
bool ObjCGenericList);
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
SourceLocation TemplateNameLoc,
const CXXScopeSpec &SS,

View File

@ -7088,9 +7088,20 @@ public:
};
ObjCContainerKind getObjCContainerKind() const;
DeclResult actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
SourceLocation paramLoc,
SourceLocation colonLoc,
ParsedType typeBound);
ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc,
ArrayRef<Decl *> typeParams,
SourceLocation rAngleLoc);
void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList);
Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLoc,
ObjCTypeParamList *typeParamList,
IdentifierInfo *SuperName,
SourceLocation SuperLoc,
Decl * const *ProtoRefs,
@ -7124,6 +7135,7 @@ public:
Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLoc,
ObjCTypeParamList *typeParamList,
IdentifierInfo *CategoryName,
SourceLocation CategoryLoc,
Decl * const *ProtoRefs,
@ -7147,9 +7159,10 @@ public:
ArrayRef<Decl *> Decls);
DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
IdentifierInfo **IdentList,
SourceLocation *IdentLocs,
unsigned NumElts);
IdentifierInfo **IdentList,
SourceLocation *IdentLocs,
ArrayRef<ObjCTypeParamList *> TypeParamLists,
unsigned NumElts);
DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
const IdentifierLocPair *IdentList,

View File

@ -413,6 +413,7 @@ namespace clang {
#define LINKAGESPEC(DERIVED, BASE)
#define OBJCCOMPATIBLEALIAS(DERIVED, BASE)
#define OBJCMETHOD(DERIVED, BASE)
#define OBJCTYPEPARAM(DERIVED, BASE)
#define OBJCIVAR(DERIVED, BASE)
#define OBJCPROPERTY(DERIVED, BASE)
#define OBJCPROPERTYIMPL(DERIVED, BASE)

View File

@ -1105,7 +1105,9 @@ namespace clang {
/// \brief An OMPThreadPrivateDecl record.
DECL_OMP_THREADPRIVATE,
/// \brief An EmptyDecl record.
DECL_EMPTY
DECL_EMPTY,
/// \brief An ObjCTypeParamDecl record.
DECL_OBJC_TYPE_PARAM,
};
/// \brief Record codes for each kind of statement or expression.

View File

@ -5951,6 +5951,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
= ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
SourceLocation(),
&Idents.get("Protocol"),
/*typeParamList=*/nullptr,
/*PrevDecl=*/nullptr,
SourceLocation(), true);
}

View File

@ -240,6 +240,9 @@ namespace {
void dumpTemplateArgument(const TemplateArgument &A,
SourceRange R = SourceRange());
// Objective-C utilities.
void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams);
// Types
void VisitComplexType(const ComplexType *T) {
dumpTypeAsChild(T->getElementType());
@ -463,6 +466,7 @@ namespace {
// ObjC Decls
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
void VisitObjCMethodDecl(const ObjCMethodDecl *D);
void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
@ -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.
//===----------------------------------------------------------------------===//
@ -1457,9 +1473,17 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
dumpStmt(D->getBody());
}
void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
dumpName(D);
if (D->hasExplicitBound())
OS << " bounded";
dumpType(D->getUnderlyingType());
}
void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
dumpName(D);
dumpDeclRef(D->getClassInterface());
dumpObjCTypeParamList(D->getTypeParamList());
dumpDeclRef(D->getImplementation());
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
@ -1482,6 +1506,7 @@ void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
dumpName(D);
dumpObjCTypeParamList(D->getTypeParamListAsWritten());
dumpDeclRef(D->getSuperClass(), "super");
dumpDeclRef(D->getImplementation());

View File

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

View File

@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case TypeAliasTemplate:
case UnresolvedUsingTypename:
case TemplateTypeParm:
case ObjCTypeParam:
return IDNS_Ordinary | IDNS_Type;
case UsingShadow:

View File

@ -239,6 +239,26 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
void ObjCInterfaceDecl::anchor() { }
ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const {
// If this particular declaration has a type parameter list, return it.
if (ObjCTypeParamList *written = getTypeParamListAsWritten())
return written;
// If there is a definition, return its type parameter list.
if (const ObjCInterfaceDecl *def = getDefinition())
return def->getTypeParamListAsWritten();
// Otherwise, look at previous declarations to determine whether any
// of them has a type parameter list, skipping over those
// declarations that do not.
for (auto decl = getPreviousDecl(); decl; decl = decl->getPreviousDecl()) {
if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten())
return written;
}
return nullptr;
}
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
/// with name 'PropertyId' in the primary class; including those in protocols
/// (direct or indirect) used by the primary class.
@ -1136,6 +1156,62 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
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
//===----------------------------------------------------------------------===//
@ -1144,11 +1220,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
ObjCTypeParamList *typeParamList,
ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc,
bool isInternal){
ObjCInterfaceDecl *Result = new (C, DC)
ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal);
ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
isInternal);
Result->Data.setInt(!C.getLangOpts().Modules);
C.getObjCInterfaceType(Result, PrevDecl);
return Result;
@ -1159,6 +1237,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr,
SourceLocation(),
nullptr,
nullptr,
SourceLocation(),
nullptr, false);
Result->Data.setInt(!C.getLangOpts().Modules);
@ -1167,11 +1246,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
SourceLocation AtLoc, IdentifierInfo *Id,
ObjCTypeParamList *typeParamList,
SourceLocation CLoc,
ObjCInterfaceDecl *PrevDecl,
bool IsInternal)
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
redeclarable_base(C), TypeForDecl(nullptr), Data() {
redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(typeParamList),
Data() {
setPreviousDecl(PrevDecl);
// Copy the 'data' pointer over.
@ -1179,6 +1260,12 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
Data = PrevDecl->Data;
setImplicit(IsInternal);
// Update the declaration context of the type parameters.
if (typeParamList) {
for (auto typeParam : *typeParamList)
typeParam->setDeclContext(this);
}
}
void ObjCInterfaceDecl::LoadExternalDefinition() const {
@ -1648,17 +1735,39 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
void ObjCCategoryDecl::anchor() { }
ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc,
SourceLocation IvarRBraceLoc)
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
ClassInterface(IDecl), TypeParamList(typeParamList),
NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc),
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc)
{
// Set the declaration context of each of the type parameters.
if (typeParamList) {
for (auto typeParam : *typeParamList) {
typeParam->setDeclContext(this);
}
}
}
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id,
ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc,
SourceLocation IvarRBraceLoc) {
ObjCCategoryDecl *CatDecl =
new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
IDecl, IvarLBraceLoc, IvarRBraceLoc);
IDecl, typeParamList, IvarLBraceLoc,
IvarRBraceLoc);
if (IDecl) {
// Link this category into its class's category list.
CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
@ -1676,7 +1785,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
SourceLocation(), SourceLocation(),
nullptr, nullptr);
nullptr, nullptr, nullptr);
}
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {

View File

@ -44,6 +44,8 @@ namespace {
void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
QualType T);
void PrintObjCTypeParams(ObjCTypeParamList *Params);
public:
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation = 0, bool PrintInstantiation = false)
@ -962,6 +964,25 @@ void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx,
Out << ')';
}
void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) {
Out << "<";
unsigned First = true;
for (auto *Param : *Params) {
if (First) {
First = false;
} else {
Out << ", ";
}
Out << Param->getDeclName().getAsString();
if (Param->hasExplicitBound()) {
Out << " : " << Param->getUnderlyingType().getAsString(Policy);
}
}
Out << ">";
}
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
if (OMD->isInstanceMethod())
Out << "- ";
@ -1037,14 +1058,24 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
ObjCInterfaceDecl *SID = OID->getSuperClass();
if (!OID->isThisDeclarationADefinition()) {
Out << "@class " << I << ";";
Out << "@class " << I;
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
PrintObjCTypeParams(TypeParams);
}
Out << ";";
return;
}
bool eolnOut = false;
Out << "@interface " << I;
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
PrintObjCTypeParams(TypeParams);
}
if (SID)
Out << "@interface " << I << " : " << *SID;
else
Out << "@interface " << I;
Out << " : " << OID->getSuperClass()->getName();
// Protocols?
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
@ -1107,7 +1138,11 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *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) {
Out << "{\n";
Indentation += Policy.Indentation;

View File

@ -79,6 +79,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Captured:
case Decl::ClassScopeFunctionSpecialization:
case Decl::UsingShadow:
case Decl::ObjCTypeParam:
llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Function: // void X();
case Decl::Record: // struct/union/class X;

View File

@ -96,14 +96,17 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
///
/// objc-class-declaration:
/// '@' 'class' identifier-list ';'
/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
///
/// objc-class-forward-decl:
/// identifier objc-type-parameter-list[opt]
///
Parser::DeclGroupPtrTy
Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ConsumeToken(); // the identifier "class"
SmallVector<IdentifierInfo *, 8> ClassNames;
SmallVector<SourceLocation, 8> ClassLocs;
SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
while (1) {
MaybeSkipAttributes(tok::objc_class);
@ -116,6 +119,14 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ClassLocs.push_back(Tok.getLocation());
ConsumeToken();
// Parse the optional objc-type-parameter-list.
ObjCTypeParamList *TypeParams = nullptr;
if (Tok.is(tok::less)) {
TypeParams = parseObjCTypeParamList();
if (TypeParams)
Actions.popObjCTypeParamList(getCurScope(), TypeParams);
}
ClassTypeParams.push_back(TypeParams);
if (!TryConsumeToken(tok::comma))
break;
}
@ -126,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
ClassLocs.data(),
ClassTypeParams,
ClassNames.size());
}
@ -154,15 +166,15 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
/// objc-category-interface
///
/// objc-class-interface:
/// '@' 'interface' identifier objc-superclass[opt]
/// objc-protocol-refs[opt]
/// '@' 'interface' identifier objc-type-parameter-list[opt]
/// objc-superclass[opt] objc-protocol-refs[opt]
/// objc-class-instance-variables[opt]
/// objc-interface-decl-list
/// @end
///
/// objc-category-interface:
/// '@' 'interface' identifier '(' identifier[opt] ')'
/// objc-protocol-refs[opt]
/// '@' 'interface' identifier objc-type-parameter-list[opt]
/// '(' identifier[opt] ')' objc-protocol-refs[opt]
/// objc-interface-decl-list
/// @end
///
@ -202,7 +214,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
if (Tok.is(tok::l_paren) &&
// Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
// case, LAngleLoc will be valid and ProtocolIdents will capture the
// protocol references (that have not yet been resolved).
SourceLocation LAngleLoc, EndProtoLoc;
SmallVector<IdentifierLocPair, 8> ProtocolIdents;
ObjCTypeParamList *typeParameterList = nullptr;
if (Tok.is(tok::less)) {
typeParameterList = parseObjCTypeParamListOrProtocolRefs(LAngleLoc,
ProtocolIdents,
EndProtoLoc);
}
if (Tok.is(tok::l_paren) &&
!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
BalancedDelimiterTracker T(*this, tok::l_paren);
@ -237,7 +262,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
}
// Next, we need to check for any protocol references.
SourceLocation LAngleLoc, EndProtoLoc;
assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
SmallVector<Decl *, 8> ProtocolRefs;
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
@ -248,6 +273,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
Decl *CategoryType =
Actions.ActOnStartCategoryInterface(AtLoc,
nameId, nameLoc,
typeParameterList,
categoryId, categoryLoc,
ProtocolRefs.data(),
ProtocolRefs.size(),
@ -258,6 +284,10 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
if (typeParameterList)
Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
return CategoryType;
}
// Parse a class interface.
@ -281,21 +311,44 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
}
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken();
} else if (typeParameterList) {
// An objc-type-parameter-list is ambiguous with an objc-protocol-refs
// in an @interface without a specified superclass, so such classes
// are ill-formed. We have determined that we have an
// objc-type-parameter-list but no superclass, so complain and record
// as if we inherited from NSObject.
SourceLocation insertLoc = PP.getLocForEndOfToken(PrevTokLocation);
Diag(insertLoc, diag::err_objc_parameterized_class_without_base)
<< nameId
<< FixItHint::CreateInsertion(insertLoc, " : NSObject");
superClassId = PP.getIdentifierInfo("NSObject");
superClassLoc = Tok.getLocation();
}
// Next, we need to check for any protocol references.
SmallVector<Decl *, 8> ProtocolRefs;
SmallVector<SourceLocation, 8> ProtocolLocs;
SourceLocation LAngleLoc, EndProtoLoc;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
LAngleLoc, EndProtoLoc))
if (LAngleLoc.isValid()) {
// We already parsed the protocols named when we thought we had a
// type parameter list. Translate them into actual protocol references.
for (const auto &pair : ProtocolIdents) {
ProtocolLocs.push_back(pair.second);
}
Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
/*ForObjCContainer=*/true,
&ProtocolIdents[0], ProtocolIdents.size(),
ProtocolRefs);
} else if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
LAngleLoc, EndProtoLoc)) {
return nullptr;
}
if (Tok.isNot(tok::less))
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
Decl *ClsType =
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList,
superClassId, superClassLoc,
ProtocolRefs.data(), ProtocolRefs.size(),
ProtocolLocs.data(),
@ -305,6 +358,10 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
if (typeParameterList)
Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
return ClsType;
}
@ -339,6 +396,172 @@ static void 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:
/// empty
/// objc-interface-decl-list objc-property-decl [OBJC2]
@ -1311,7 +1534,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
}
// Consume the '>'.
if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true))
if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true,
/*ObjCGenericList=*/false))
return true;
// Convert the list of protocols identifiers into a list of protocol decls.
@ -1598,6 +1822,22 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
Decl *ObjCImpDecl = nullptr;
// Neither a type parameter list nor a list of protocol references is
// permitted here. Parse and diagnose them.
if (Tok.is(tok::less)) {
SourceLocation lAngleLoc, rAngleLoc;
SmallVector<IdentifierLocPair, 8> protocolIdents;
SourceLocation diagLoc = Tok.getLocation();
if (parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents,
rAngleLoc)) {
Diag(diagLoc, diag::err_objc_parameterized_implementation)
<< SourceRange(diagLoc, PrevTokLocation);
} else if (lAngleLoc.isValid()) {
Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
<< FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
}
}
if (Tok.is(tok::l_paren)) {
// we have a category implementation.
ConsumeParen();

View File

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

View File

@ -3029,7 +3029,9 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
case Decl::Import:
return CXCursor_ModuleImportDecl;
case Decl::ObjCTypeParam: return CXCursor_TemplateTypeParameter;
default:
if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {

View File

@ -20,12 +20,15 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "TypeLocBuilder.h"
using namespace clang;
@ -461,9 +464,214 @@ static void diagnoseUseOfProtocols(Sema &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::
ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
ObjCTypeParamList *typeParamList,
IdentifierInfo *SuperName, SourceLocation SuperLoc,
Decl * const *ProtoRefs, unsigned NumProtoRefs,
const SourceLocation *ProtoLocs,
@ -498,10 +706,47 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
ClassName = PrevIDecl->getIdentifier();
}
// If there was a forward declaration with type parameters, check
// for consistency.
if (PrevIDecl) {
if (ObjCTypeParamList *prevTypeParamList = PrevIDecl->getTypeParamList()) {
if (typeParamList) {
// Both have type parameter lists; check for consistency.
if (checkTypeParamListConsistency(*this, prevTypeParamList,
typeParamList,
TypeParamListContext::Definition)) {
typeParamList = nullptr;
}
} else {
Diag(ClassLoc, diag::err_objc_parameterized_forward_class_first)
<< ClassName;
Diag(prevTypeParamList->getLAngleLoc(), diag::note_previous_decl)
<< ClassName;
// Clone the type parameter list.
SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams;
for (auto typeParam : *prevTypeParamList) {
clonedTypeParams.push_back(
ObjCTypeParamDecl::Create(
Context,
CurContext,
SourceLocation(),
typeParam->getIdentifier(),
SourceLocation(),
Context.getTrivialTypeSourceInfo(typeParam->getUnderlyingType())));
}
typeParamList = ObjCTypeParamList::create(Context,
SourceLocation(),
clonedTypeParams,
SourceLocation());
}
}
}
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
PrevIDecl, ClassLoc);
typeParamList, PrevIDecl, ClassLoc);
if (PrevIDecl) {
// Class already seen. Was it a definition?
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
@ -906,6 +1151,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
Decl *Sema::
ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
ObjCTypeParamList *typeParamList,
IdentifierInfo *CategoryName,
SourceLocation CategoryLoc,
Decl * const *ProtoRefs,
@ -925,7 +1171,8 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
// the enclosing method declarations. We mark the decl invalid
// to make it clear that this isn't a valid AST.
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
ClassLoc, CategoryLoc, CategoryName,IDecl);
ClassLoc, CategoryLoc, CategoryName,
IDecl, typeParamList);
CDecl->setInvalidDecl();
CurContext->addDecl(CDecl);
@ -951,8 +1198,28 @@ ActOnStartCategoryInterface(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,
ClassLoc, CategoryLoc, CategoryName, IDecl);
ClassLoc, CategoryLoc, CategoryName, IDecl,
typeParamList);
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
@ -987,7 +1254,8 @@ Decl *Sema::ActOnStartCategoryImplementation(
// Create and install one.
CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, AtCatImplLoc,
ClassLoc, CatLoc,
CatName, IDecl);
CatName, IDecl,
/*typeParamList=*/nullptr);
CatIDecl->setImplicit();
}
}
@ -1101,7 +1369,8 @@ Decl *Sema::ActOnStartClassImplementation(
// FIXME: Do we support attributes on the @implementation? If so we should
// copy them over.
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
ClassName, /*PrevDecl=*/nullptr, ClassLoc,
ClassName, /*typeParamList=*/nullptr,
/*PrevDecl=*/nullptr, ClassLoc,
true);
IDecl->startDefinition();
if (SDecl) {
@ -2083,6 +2352,7 @@ Sema::DeclGroupPtrTy
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
IdentifierInfo **IdentList,
SourceLocation *IdentLocs,
ArrayRef<ObjCTypeParamList *> TypeParamLists,
unsigned NumElts) {
SmallVector<Decl *, 8> DeclsInGroup;
for (unsigned i = 0; i != NumElts; ++i) {
@ -2137,9 +2407,33 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
ClassName = PrevIDecl->getIdentifier();
}
// If this forward declaration has type parameters, compare them with the
// type parameters of the previous declaration.
ObjCTypeParamList *TypeParams = TypeParamLists[i];
if (PrevIDecl && TypeParams) {
if (ObjCTypeParamList *PrevTypeParams = PrevIDecl->getTypeParamList()) {
// Check for consistency with the previous declaration.
if (checkTypeParamListConsistency(
*this, PrevTypeParams, TypeParams,
TypeParamListContext::ForwardDeclaration)) {
TypeParams = nullptr;
}
} else if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
// The @interface does not have type parameters. Complain.
Diag(IdentLocs[i], diag::err_objc_parameterized_forward_class)
<< ClassName
<< TypeParams->getSourceRange();
Diag(Def->getLocation(), diag::note_defined_here)
<< ClassName;
TypeParams = nullptr;
}
}
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
ClassName, PrevIDecl, IdentLocs[i]);
ClassName, TypeParams, PrevIDecl,
IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
PushOnScopeChains(IDecl, TUScope);

View File

@ -133,7 +133,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
ObjCInterfaceDecl::Create (Context,
Context.getTranslationUnitDecl(),
SourceLocation(), NSIdent,
nullptr, SourceLocation());
nullptr, nullptr, SourceLocation());
Ty = Context.getObjCInterfaceType(NSStringIDecl);
Context.setObjCNSStringType(Ty);
}
@ -208,7 +208,8 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
S.NSNumberDecl = ObjCInterfaceDecl::Create(CX,
CX.getTranslationUnitDecl(),
SourceLocation(), NSNumberId,
nullptr, SourceLocation());
nullptr, nullptr,
SourceLocation());
} else {
// Otherwise, require a declaration of NSNumber.
S.Diag(Loc, diag::err_undeclared_nsnumber);
@ -475,7 +476,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
NSStringDecl = ObjCInterfaceDecl::Create(Context, TU,
SourceLocation(),
NSStringId,
nullptr, SourceLocation());
nullptr, nullptr,
SourceLocation());
} else {
Diag(SR.getBegin(), diag::err_undeclared_nsstring);
return ExprError();
@ -591,7 +593,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
DeclContext *TU = Context.getTranslationUnitDecl();
NSValueDecl = ObjCInterfaceDecl::Create(Context, TU,
SourceLocation(), NSValueId,
nullptr, SourceLocation());
nullptr, nullptr,
SourceLocation());
} else {
// Otherwise, require a declaration of NSValue.
Diag(SR.getBegin(), diag::err_undeclared_nsvalue);
@ -755,7 +758,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Context.getTranslationUnitDecl(),
SourceLocation(),
NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
nullptr, SourceLocation());
nullptr, nullptr, SourceLocation());
if (!NSArrayDecl) {
Diag(SR.getBegin(), diag::err_undeclared_nsarray);
@ -870,7 +873,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
Context.getTranslationUnitDecl(),
SourceLocation(),
NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
nullptr, SourceLocation());
nullptr, nullptr, SourceLocation());
if (!NSDictionaryDecl) {
Diag(SR.getBegin(), diag::err_undeclared_nsdictionary);

View File

@ -221,6 +221,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
// redeclarable.
case Decl::ImplicitParam:
case Decl::ParmVar:
case Decl::ObjCTypeParam:
return false;
}

View File

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

View File

@ -117,6 +117,7 @@ namespace clang {
// FIXME: Put in the same order is DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
void VisitObjCIvarDecl(ObjCIvarDecl *D);
@ -131,6 +132,22 @@ namespace clang {
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
/// Add an Objective-C type parameter list to the given record.
void AddObjCTypeParamList(ObjCTypeParamList *typeParams) {
// Empty type parameter list.
if (!typeParams) {
Record.push_back(0);
return;
}
Record.push_back(typeParams->size());
for (auto typeParam : *typeParams) {
Writer.AddDeclRef(typeParam, Record);
}
Writer.AddSourceLocation(typeParams->getLAngleLoc(), Record);
Writer.AddSourceLocation(typeParams->getRAngleLoc(), Record);
}
void AddFunctionDefinition(const FunctionDecl *FD) {
assert(FD->doesThisDeclarationHaveABody());
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
@ -562,6 +579,13 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Code = serialization::DECL_OBJC_METHOD;
}
void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
VisitTypedefNameDecl(D);
Writer.AddSourceLocation(D->ColonLoc, Record);
Code = serialization::DECL_OBJC_TYPE_PARAM;
}
void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
VisitNamedDecl(D);
Writer.AddSourceLocation(D->getAtStartLoc(), Record);
@ -573,6 +597,7 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
VisitRedeclarable(D);
VisitObjCContainerDecl(D);
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
AddObjCTypeParamList(D->TypeParamList);
Record.push_back(D->isThisDeclarationADefinition());
if (D->isThisDeclarationADefinition()) {
@ -660,6 +685,7 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
Writer.AddDeclRef(D->getClassInterface(), Record);
AddObjCTypeParamList(D->TypeParamList);
Record.push_back(D->protocol_size());
for (const auto *I : D->protocols())
Writer.AddDeclRef(I, Record);

View File

@ -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 &lt;T : id, U : NSObject *&gt; : NSObject
/// A
@interface A<T : id, U : NSObject *> : NSObject
@end

View File

@ -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

View File

@ -17,7 +17,7 @@
@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 '>'}}
// rdar://13920026

View File

@ -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 *')}}
}

View File

@ -5038,6 +5038,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::ObjCTypeParam:
return C;
// Declaration kinds that don't make any sense here, but are
@ -6321,6 +6322,7 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
case Decl::ObjCProperty:
case Decl::ObjCPropertyImpl:
case Decl::ObjCProtocol:
case Decl::ObjCTypeParam:
return CXLanguage_ObjC;
case Decl::CXXConstructor:
case Decl::CXXConversion: