summaryrefslogtreecommitdiffstats
path: root/clang/lib/Parse/ParseObjc.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-07-07 03:58:14 +0000
committerDouglas Gregor <dgregor@apple.com>2015-07-07 03:58:14 +0000
commit9bda6cff20276f67c02d0d2814ef44c2d62ecd89 (patch)
tree42cdccf290e6507ad745f4b0a838e76a6f8e32d0 /clang/lib/Parse/ParseObjc.cpp
parentc5e07f5c115ed486f57db957447086c1b0023385 (diff)
downloadbcm5719-llvm-9bda6cff20276f67c02d0d2814ef44c2d62ecd89.tar.gz
bcm5719-llvm-9bda6cff20276f67c02d0d2814ef44c2d62ecd89.zip
C++ support for Objective-C lightweight generics.
Teach C++'s tentative parsing to handle specializations of Objective-C class types (e.g., NSArray<NSString *>) as well as Objective-C protocol qualifiers (id<NSCopying>) by extending type-annotation tokens to handle this case. As part of this, remove Objective-C protocol qualifiers from the declaration specifiers, which never really made sense: instead, provide Sema entry points to make them part of the type annotation token. Among other things, this properly diagnoses bogus types such as "<NSCopying> id" which should have been written as "id <NSCopying>". Implements template instantiation support for, e.g., NSArray<T>* in C++. Note that parameterized classes are not templates in the C++ sense, so that cannot (for example) be used as a template argument for a template template parameter. Part of rdar://problem/6294649. llvm-svn: 241545
Diffstat (limited to 'clang/lib/Parse/ParseObjc.cpp')
-rw-r--r--clang/lib/Parse/ParseObjc.cpp289
1 files changed, 198 insertions, 91 deletions
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 669c0653df8..3dbecd09008 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -267,7 +267,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
- LAngleLoc, EndProtoLoc))
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true))
return nullptr;
Decl *CategoryType =
@@ -293,8 +294,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Parse a class interface.
IdentifierInfo *superClassId = nullptr;
SourceLocation superClassLoc;
- DeclSpec superClassDS(AttrFactory);
-
+ SourceLocation typeArgsLAngleLoc;
+ SmallVector<ParsedType, 4> typeArgs;
+ SourceLocation typeArgsRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
if (Tok.is(tok::colon)) { // a super class is specified.
ConsumeToken();
@@ -315,51 +319,50 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Type arguments for the superclass or protocol conformances.
if (Tok.is(tok::less)) {
- ParseObjCTypeArgsOrProtocolQualifiers(superClassDS,
+ parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ LAngleLoc,
+ protocols,
+ protocolLocs,
+ EndProtoLoc,
+ /*consumeLastToken=*/true,
/*warnOnIncompleteProtocols=*/true);
}
}
// Next, we need to check for any protocol references.
- SmallVector<Decl *, 8> ProtocolRefs;
- SmallVector<SourceLocation, 8> ProtocolLocs;
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 (auto protocols = superClassDS.getProtocolQualifiers()) {
- // We already parsed the protocols named when we thought we had a
- // type argument list (for a specialized superclass). Treat them
- // as actual protocol references.
- unsigned numProtocols = superClassDS.getNumProtocolQualifiers();
- ProtocolRefs.append(protocols, protocols + numProtocols);
- ProtocolLocs.append(superClassDS.getProtocolLocs(),
- superClassDS.getProtocolLocs() + numProtocols);
- LAngleLoc = superClassDS.getProtocolLAngleLoc();
- EndProtoLoc = superClassDS.getLocEnd();
- } else if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
- LAngleLoc, EndProtoLoc)) {
+ if (!ProtocolIdents.empty()) {
+ // 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(),
+ protocols);
+ }
+ } else if (protocols.empty() && Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true)) {
return nullptr;
}
if (Tok.isNot(tok::less))
- Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
+ Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc);
Decl *ClsType =
Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc,
typeParameterList, superClassId,
superClassLoc,
- superClassDS.getObjCTypeArgs(),
- superClassDS.getObjCTypeArgsRange(),
- ProtocolRefs.data(), ProtocolRefs.size(),
- ProtocolLocs.data(),
+ typeArgs,
+ SourceRange(typeArgsLAngleLoc,
+ typeArgsRAngleLoc),
+ protocols.data(), protocols.size(),
+ protocolLocs.data(),
EndProtoLoc, attrs.getList());
if (Tok.is(tok::l_brace))
@@ -1515,7 +1518,8 @@ bool Parser::
ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
SmallVectorImpl<SourceLocation> &ProtocolLocs,
bool WarnOnDeclarations, bool ForObjCContainer,
- SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
+ SourceLocation &LAngleLoc, SourceLocation &EndLoc,
+ bool consumeLastToken) {
assert(Tok.is(tok::less) && "expected <");
LAngleLoc = ConsumeToken(); // the "<"
@@ -1545,7 +1549,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
}
// Consume the '>'.
- if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true,
+ if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken,
/*ObjCGenericList=*/false))
return true;
@@ -1556,30 +1560,43 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
return false;
}
-/// \brief Parse the Objective-C protocol qualifiers that follow a typename
-/// in a decl-specifier-seq, starting at the '<'.
-bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
+TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C");
- SourceLocation LAngleLoc, EndProtoLoc;
- SmallVector<Decl *, 8> ProtocolDecl;
- SmallVector<SourceLocation, 8> ProtocolLocs;
- bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
- false, LAngleLoc, EndProtoLoc);
- DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
- ProtocolLocs.data(), LAngleLoc);
- if (EndProtoLoc.isValid())
- DS.SetRangeEnd(EndProtoLoc);
- return Result;
+
+ SourceLocation lAngleLoc;
+ SmallVector<Decl *, 8> protocols;
+ SmallVector<SourceLocation, 8> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
+ lAngleLoc, rAngleLoc,
+ /*consumeLastToken=*/true);
+ TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
+ protocols,
+ protocolLocs,
+ rAngleLoc);
+ if (result.isUsable()) {
+ Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
+ << FixItHint::CreateInsertion(lAngleLoc, "id")
+ << SourceRange(lAngleLoc, rAngleLoc);
+ }
+
+ return result;
}
/// Parse Objective-C type arguments or protocol qualifiers.
///
/// objc-type-arguments:
-/// '<' type-name (',' type-name)* '>'
-///
-void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
- DeclSpec &DS,
+/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
+///
+void Parser::parseObjCTypeArgsOrProtocolQualifiers(
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SmallVectorImpl<SourceLocation> &protocolLocs,
+ SourceLocation &protocolRAngleLoc,
+ bool consumeLastToken,
bool warnOnIncompleteProtocols) {
assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
SourceLocation lAngleLoc = ConsumeToken();
@@ -1588,7 +1605,7 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
// identifiers, which might be types or might be protocols.
bool allSingleIdentifiers = true;
SmallVector<IdentifierInfo *, 4> identifiers;
- SmallVector<SourceLocation, 4> identifierLocs;
+ SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
// Parse a list of comma-separated identifiers, bailing out if we
// see something different.
@@ -1626,23 +1643,27 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
if (allSingleIdentifiers) {
// Parse the closing '>'.
SourceLocation rAngleLoc;
- (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
/*ObjCGenericList=*/true);
// Let Sema figure out what we parsed.
Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
- DS,
lAngleLoc,
identifiers,
identifierLocs,
rAngleLoc,
+ typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolRAngleLoc,
warnOnIncompleteProtocols);
return;
}
// We syntactically matched a type argument, so commit to parsing
// type arguments.
- SmallVector<ParsedType, 4> typeArgs;
// Convert the identifiers into type arguments.
bool invalid = false;
@@ -1650,7 +1671,19 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
ParsedType typeArg
= Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
if (typeArg) {
- typeArgs.push_back(typeArg);
+ DeclSpec DS(AttrFactory);
+ const char *prevSpec = nullptr;
+ unsigned diagID;
+ DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
+ typeArg, Actions.getASTContext().getPrintingPolicy());
+
+ // Form a declarator to turn this into a type.
+ Declarator D(DS, Declarator::TypeNameContext);
+ TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
+ if (fullTypeArg.isUsable())
+ typeArgs.push_back(fullTypeArg.get());
+ else
+ invalid = true;
} else {
invalid = true;
}
@@ -1659,6 +1692,14 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
// Continue parsing type-names.
do {
TypeResult typeArg = ParseTypeName();
+
+ // Consume the '...' for a pack expansion.
+ SourceLocation ellipsisLoc;
+ TryConsumeToken(tok::ellipsis, ellipsisLoc);
+ if (typeArg.isUsable() && ellipsisLoc.isValid()) {
+ typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
+ }
+
if (typeArg.isUsable()) {
typeArgs.push_back(typeArg.get());
} else {
@@ -1668,53 +1709,105 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
// Parse the closing '>'.
SourceLocation rAngleLoc;
- (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
/*ObjCGenericList=*/true);
- if (invalid)
+ if (invalid) {
+ typeArgs.clear();
return;
+ }
- // Update the DeclSpec appropriately.
- DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+ // Record left/right angle locations.
+ typeArgsLAngleLoc = lAngleLoc;
+ typeArgsRAngleLoc = rAngleLoc;
}
-void Parser::ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS) {
+void Parser::parseObjCTypeArgsAndProtocolQualifiers(
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SmallVectorImpl<SourceLocation> &protocolLocs,
+ SourceLocation &protocolRAngleLoc,
+ bool consumeLastToken) {
assert(Tok.is(tok::less));
- ParseObjCTypeArgsOrProtocolQualifiers(DS,
+ // Parse the first angle-bracket-delimited clause.
+ parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolLocs,
+ protocolRAngleLoc,
+ consumeLastToken,
/*warnOnIncompleteProtocols=*/false);
// An Objective-C object pointer followed by type arguments
// can then be followed again by a set of protocol references, e.g.,
// \c NSArray<NSView><NSTextDelegate>
- if (Tok.is(tok::less)) {
- if (DS.getProtocolQualifiers()) {
+ if ((consumeLastToken && Tok.is(tok::less)) ||
+ (!consumeLastToken && NextToken().is(tok::less))) {
+ // If we aren't consuming the last token, the prior '>' is still hanging
+ // there. Consume it before we parse the protocol qualifiers.
+ if (!consumeLastToken)
+ ConsumeToken();
+
+ if (!protocols.empty()) {
+ SkipUntilFlags skipFlags = SkipUntilFlags();
+ if (!consumeLastToken)
+ skipFlags = skipFlags | StopBeforeMatch;
Diag(Tok, diag::err_objc_type_args_after_protocols)
- << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
- SkipUntil(tok::greater, tok::greatergreater);
+ << SourceRange(protocolLAngleLoc, protocolRAngleLoc);
+ SkipUntil(tok::greater, tok::greatergreater, skipFlags);
} else {
- ParseObjCProtocolQualifiers(DS);
+ ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*WarnOnDeclarations=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ consumeLastToken);
}
}
}
-TypeResult Parser::ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
- ParsedType type) {
+TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
+ SourceLocation loc,
+ ParsedType type,
+ bool consumeLastToken,
+ SourceLocation &endLoc) {
assert(Tok.is(tok::less));
-
- // Create declaration specifiers and set the type as the type specifier.
- DeclSpec DS(AttrFactory);
- const char *prevSpec = nullptr;
- unsigned diagID;
- DS.SetTypeSpecType(TST_typename, loc, prevSpec, diagID, type,
- Actions.getASTContext().getPrintingPolicy());
+ SourceLocation typeArgsLAngleLoc;
+ SmallVector<ParsedType, 4> typeArgs;
+ SourceLocation typeArgsRAngleLoc;
+ SourceLocation protocolLAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ SourceLocation protocolRAngleLoc;
// Parse type arguments and protocol qualifiers.
- ParseObjCTypeArgsAndProtocolQualifiers(DS);
-
- // Form a declarator to turn this into a type.
- Declarator D(DS, Declarator::TypeNameContext);
- return Actions.ActOnTypeName(getCurScope(), D);
+ parseObjCTypeArgsAndProtocolQualifiers(typeArgsLAngleLoc, typeArgs,
+ typeArgsRAngleLoc, protocolLAngleLoc,
+ protocols, protocolLocs,
+ protocolRAngleLoc, consumeLastToken);
+
+ // Compute the location of the last token.
+ if (consumeLastToken)
+ endLoc = PrevTokLocation;
+ else
+ endLoc = Tok.getLocation();
+
+ return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
+ getCurScope(),
+ loc,
+ type,
+ typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolLocs,
+ protocolRAngleLoc);
}
void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
@@ -1926,7 +2019,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
- LAngleLoc, EndProtoLoc))
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true))
return DeclGroupPtrTy();
Decl *ProtoType =
@@ -2020,9 +2114,14 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
rparenLoc = ConsumeParen();
if (Tok.is(tok::less)) { // we have illegal '<' try to recover
Diag(Tok, diag::err_unexpected_protocol_qualifier);
- AttributeFactory attr;
- DeclSpec DS(attr);
- (void)ParseObjCProtocolQualifiers(DS);
+ SourceLocation protocolLAngleLoc, protocolRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*warnOnIncompleteProtocols=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ /*consumeLastToken=*/true);
}
ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
AtLoc, nameId, nameLoc, categoryId,
@@ -2050,10 +2149,15 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
Diag(Tok, diag::err_unexpected_protocol_qualifier);
- // try to recover.
- AttributeFactory attr;
- DeclSpec DS(attr);
- (void)ParseObjCProtocolQualifiers(DS);
+
+ SourceLocation protocolLAngleLoc, protocolRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*warnOnIncompleteProtocols=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ /*consumeLastToken=*/true);
}
}
assert(ObjCImpDecl);
@@ -2873,8 +2977,11 @@ ExprResult Parser::ParseObjCMessageExpression() {
// Parse type arguments and protocol qualifiers.
if (Tok.is(tok::less)) {
+ SourceLocation NewEndLoc;
TypeResult NewReceiverType
- = ParseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType);
+ = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
+ /*consumeLastToken=*/true,
+ NewEndLoc);
if (!NewReceiverType.isUsable()) {
SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
OpenPOWER on IntegriCloud