diff options
author | Douglas Gregor <dgregor@apple.com> | 2015-07-07 03:58:14 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2015-07-07 03:58:14 +0000 |
commit | 9bda6cff20276f67c02d0d2814ef44c2d62ecd89 (patch) | |
tree | 42cdccf290e6507ad745f4b0a838e76a6f8e32d0 /clang/lib/Parse/ParseObjc.cpp | |
parent | c5e07f5c115ed486f57db957447086c1b0023385 (diff) | |
download | bcm5719-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.cpp | 289 |
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(); |