summaryrefslogtreecommitdiffstats
path: root/clang/lib/Parse
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Parse')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp50
-rw-r--r--clang/lib/Parse/ParseObjc.cpp146
-rw-r--r--clang/lib/Parse/ParseTentative.cpp2
3 files changed, 170 insertions, 28 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index d843e801b63..fdd10522ee5 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2886,11 +2886,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken(); // The typename
- // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
- // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
- // Objective-C interface.
- if (Tok.is(tok::less) && getLangOpts().ObjC1)
- ParseObjCProtocolQualifiers(DS);
+ // Objective-C supports type arguments and protocol references
+ // following an Objective-C object pointer type. Handle either
+ // one of them.
+ if (Tok.is(tok::less) && getLangOpts().ObjC1) {
+ ParseObjCTypeArgsOrProtocolQualifiers(
+ DS, /*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()) {
+ Diag(Tok, diag::err_objc_type_args_after_protocols)
+ << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
+ SkipUntil(tok::greater, tok::greatergreater);
+ } else {
+ ParseObjCProtocolQualifiers(DS);
+ }
+ }
+ }
continue;
}
@@ -2997,11 +3012,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken(); // The identifier
- // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
- // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
- // Objective-C interface.
- if (Tok.is(tok::less) && getLangOpts().ObjC1)
- ParseObjCProtocolQualifiers(DS);
+ // Objective-C supports type arguments and protocol references
+ // following an Objective-C object pointer type. Handle either
+ // one of them.
+ if (Tok.is(tok::less) && getLangOpts().ObjC1) {
+ ParseObjCTypeArgsOrProtocolQualifiers(
+ DS, /*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()) {
+ Diag(Tok, diag::err_objc_type_args_after_protocols)
+ << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
+ SkipUntil(tok::greater, tok::greatergreater);
+ } else {
+ ParseObjCProtocolQualifiers(DS);
+ }
+ }
+ }
// Need to support trailing type qualifiers (e.g. "id<p> const").
// If a type specifier follows, it will be diagnosed elsewhere.
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 3ef187af8d7..0e4574056b0 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -179,7 +179,7 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
/// @end
///
/// objc-superclass:
-/// ':' identifier
+/// ':' identifier objc-type-arguments[opt]
///
/// objc-class-interface-attributes:
/// __attribute__((visibility("default")))
@@ -293,6 +293,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Parse a class interface.
IdentifierInfo *superClassId = nullptr;
SourceLocation superClassLoc;
+ DeclSpec superClassDS(AttrFactory);
if (Tok.is(tok::colon)) { // a super class is specified.
ConsumeToken();
@@ -311,18 +312,12 @@ 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();
+
+ // Type arguments for the superclass or protocol conformances.
+ if (Tok.is(tok::less)) {
+ ParseObjCTypeArgsOrProtocolQualifiers(superClassDS,
+ /*warnOnIncompleteProtocols=*/true);
+ }
}
// Next, we need to check for any protocol references.
@@ -338,6 +333,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
/*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)) {
@@ -348,8 +353,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
Decl *ClsType =
- Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList,
- superClassId, superClassLoc,
+ Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc,
+ typeParameterList, superClassId,
+ superClassLoc,
+ superClassDS.getObjCTypeArgs(),
+ superClassDS.getObjCTypeArgsRange(),
ProtocolRefs.data(), ProtocolRefs.size(),
ProtocolLocs.data(),
EndProtoLoc, attrs.getList());
@@ -1554,8 +1562,7 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
SmallVector<Decl *, 8> ProtocolDecl;
SmallVector<SourceLocation, 8> ProtocolLocs;
bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
- false,
- LAngleLoc, EndProtoLoc);
+ false, LAngleLoc, EndProtoLoc);
DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
ProtocolLocs.data(), LAngleLoc);
if (EndProtoLoc.isValid())
@@ -1563,6 +1570,111 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
return Result;
}
+/// Parse Objective-C type arguments or protocol qualifiers.
+///
+/// objc-type-arguments:
+/// '<' type-name (',' type-name)* '>'
+///
+void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
+ DeclSpec &DS,
+ bool warnOnIncompleteProtocols) {
+ assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
+ SourceLocation lAngleLoc = ConsumeToken();
+
+ // Whether all of the elements we've parsed thus far are single
+ // identifiers, which might be types or might be protocols.
+ bool allSingleIdentifiers = true;
+ SmallVector<IdentifierInfo *, 4> identifiers;
+ SmallVector<SourceLocation, 4> identifierLocs;
+
+ // Parse a list of comma-separated identifiers, bailing out if we
+ // see something different.
+ do {
+ // Parse a single identifier.
+ if (Tok.is(tok::identifier) &&
+ (NextToken().is(tok::comma) ||
+ NextToken().is(tok::greater) ||
+ NextToken().is(tok::greatergreater))) {
+ identifiers.push_back(Tok.getIdentifierInfo());
+ identifierLocs.push_back(ConsumeToken());
+ continue;
+ }
+
+ if (Tok.is(tok::code_completion)) {
+ // FIXME: Also include types here.
+ SmallVector<IdentifierLocPair, 4> identifierLocPairs;
+ for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+ identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],
+ identifierLocs[i]));
+ }
+
+ Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(),
+ identifierLocPairs.size());
+ cutOffParsing();
+ return;
+ }
+
+ allSingleIdentifiers = false;
+ break;
+ } while (TryConsumeToken(tok::comma));
+
+ // If we parsed an identifier list, semantic analysis sorts out
+ // whether it refers to protocols or to type arguments.
+ if (allSingleIdentifiers) {
+ // Parse the closing '>'.
+ SourceLocation rAngleLoc;
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+ /*ObjCGenericList=*/true);
+
+ // Let Sema figure out what we parsed.
+ Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
+ DS,
+ lAngleLoc,
+ identifiers,
+ identifierLocs,
+ rAngleLoc,
+ 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;
+ for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+ ParsedType typeArg
+ = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
+ if (typeArg) {
+ typeArgs.push_back(typeArg);
+ } else {
+ invalid = true;
+ }
+ }
+
+ // Continue parsing type-names.
+ do {
+ TypeResult typeArg = ParseTypeName();
+ if (typeArg.isUsable()) {
+ typeArgs.push_back(typeArg.get());
+ } else {
+ invalid = true;
+ }
+ } while (TryConsumeToken(tok::comma));
+
+ // Parse the closing '>'.
+ SourceLocation rAngleLoc;
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+ /*ObjCGenericList=*/true);
+
+ if (invalid)
+ return;
+
+ // Update the DeclSpec appropriately.
+ DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+}
+
void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
BalancedDelimiterTracker &T,
SmallVectorImpl<Decl *> &AllIvarDecls,
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 368cb934bba..3fdd902f07c 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1384,7 +1384,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case_typename:
// In Objective-C, we might have a protocol-qualified type.
if (getLangOpts().ObjC1 && NextToken().is(tok::less)) {
- // Tentatively parse the
+ // Tentatively parse the protocol qualifiers.
TentativeParsingAction PA(*this);
ConsumeToken(); // The type token
OpenPOWER on IntegriCloud