12 changes: 11 additions & 1 deletion clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1246,6 +1248,13 @@ class Parser : public CodeCompletionHandler {
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,
Expand Down Expand Up @@ -2469,7 +2478,8 @@ class Parser : public CodeCompletionHandler {
typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;

bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
bool ConsumeLastToken);
bool ConsumeLastToken,
bool ObjCGenericList);
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
SourceLocation TemplateNameLoc,
const CXXScopeSpec &SS,
Expand Down
19 changes: 16 additions & 3 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -7088,9 +7088,20 @@ class Sema {
};
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,
Expand Down Expand Up @@ -7124,6 +7135,7 @@ class Sema {
Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLoc,
ObjCTypeParamList *typeParamList,
IdentifierInfo *CategoryName,
SourceLocation CategoryLoc,
Decl * const *ProtoRefs,
Expand All @@ -7147,9 +7159,10 @@ class Sema {
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,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/Template.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5951,6 +5951,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
= ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
SourceLocation(),
&Idents.get("Protocol"),
/*typeParamList=*/nullptr,
/*PrevDecl=*/nullptr,
SourceLocation(), true);
}
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -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();
Expand All @@ -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());
Expand Down
56 changes: 55 additions & 1 deletion clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case TypeAliasTemplate:
case UnresolvedUsingTypename:
case TemplateTypeParm:
case ObjCTypeParam:
return IDNS_Ordinary | IDNS_Type;

case UsingShadow:
Expand Down
117 changes: 113 additions & 4 deletions clang/lib/AST/DeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -1167,18 +1246,26 @@ 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.
if (PrevDecl)
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 {
Expand Down Expand Up @@ -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();
Expand All @@ -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 {
Expand Down
45 changes: 40 additions & 5 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 << "- ";
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
268 changes: 254 additions & 14 deletions clang/lib/Parse/ParseObjc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand All @@ -126,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {

return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
ClassLocs.data(),
ClassTypeParams,
ClassNames.size());
}

Expand Down Expand Up @@ -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
///
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) &&
Expand All @@ -248,6 +273,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
Decl *CategoryType =
Actions.ActOnStartCategoryInterface(AtLoc,
nameId, nameLoc,
typeParameterList,
categoryId, categoryLoc,
ProtocolRefs.data(),
ProtocolRefs.size(),
Expand All @@ -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.
Expand All @@ -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(),
Expand All @@ -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;
}

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand Down
80 changes: 45 additions & 35 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "> >";
Expand Down Expand Up @@ -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(), " ");

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;
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()));

// 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) &&
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/SemaCodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
308 changes: 301 additions & 7 deletions clang/lib/Sema/SemaDeclObjC.cpp

Large diffs are not rendered by default.

15 changes: 9 additions & 6 deletions clang/lib/Sema/SemaExprObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
// redeclarable.
case Decl::ImplicitParam:
case Decl::ParmVar:
case Decl::ObjCTypeParam:
return false;
}

Expand Down
37 changes: 36 additions & 1 deletion clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand Down
26 changes: 26 additions & 0 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)) {
Expand Down Expand Up @@ -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);
Expand All @@ -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()) {
Expand Down Expand Up @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions clang/test/Index/comment-objc-parameterized-classes.m
Original file line number Diff line number Diff line change
@@ -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
30 changes: 30 additions & 0 deletions clang/test/PCH/objc_parameterized_classes.m
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion clang/test/Parser/objc-error-qualified-implementation.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ @implementation J < P,P > // expected-error {{@implementation declaration cannot

@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
Expand Down
192 changes: 192 additions & 0 deletions clang/test/SemaObjC/parameterized_classes.m
Original file line number Diff line number Diff line change
@@ -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 *')}}
}
2 changes: 2 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down