[SemaObjC] Be more strict while parsing type arguments and protocols

Fix a crash-on-invalid.

When parsing type arguments and protocols,
parseObjCTypeArgsOrProtocolQualifiers() calls ParseTypeName(), which tries to
find matching tokens for '[', '(', etc whenever they appear among potential
type names. If unmatched, ParseTypeName() yields a tok::eof token stream. This
leads to crashes since the parsing at this point is not expected to go beyond
the param list closing '>'.

Fix that by properly handling tok::eof in
parseObjCTypeArgsOrProtocolQualifiers() callers.

Differential Revision: https://reviews.llvm.org/D23852

rdar://problem/25063557

llvm-svn: 281383
This commit is contained in:
Bruno Cardoso Lopes
2016-09-13 20:04:35 +00:00
parent 85edca95c6
commit 218c8743c8
4 changed files with 54 additions and 2 deletions

View File

@@ -5877,7 +5877,8 @@ bool Parser::isFunctionDeclaratorIdentifierList() {
// To handle this, we check to see if the token after the first
// identifier is a "," or ")". Only then do we parse it as an
// identifier list.
&& (NextToken().is(tok::comma) || NextToken().is(tok::r_paren));
&& (!Tok.is(tok::eof) &&
(NextToken().is(tok::comma) || NextToken().is(tok::r_paren)));
}
/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator

View File

@@ -344,9 +344,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
protocols, protocolLocs, EndProtoLoc,
/*consumeLastToken=*/true,
/*warnOnIncompleteProtocols=*/true);
if (Tok.is(tok::eof))
return nullptr;
}
}
// Next, we need to check for any protocol references.
if (LAngleLoc.isValid()) {
if (!ProtocolIdents.empty()) {
@@ -1814,6 +1816,8 @@ void Parser::parseObjCTypeArgsAndProtocolQualifiers(
protocolRAngleLoc,
consumeLastToken,
/*warnOnIncompleteProtocols=*/false);
if (Tok.is(tok::eof)) // Nothing else to do here...
return;
// An Objective-C object pointer followed by type arguments
// can then be followed again by a set of protocol references, e.g.,
@@ -1862,6 +1866,9 @@ TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
protocols, protocolLocs,
protocolRAngleLoc, consumeLastToken);
if (Tok.is(tok::eof))
return true; // Invalid type result.
// Compute the location of the last token.
if (consumeLastToken)
endLoc = PrevTokLocation;

View File

@@ -1539,6 +1539,8 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
NewEndLoc);
if (NewType.isUsable())
Ty = NewType.get();
else if (Tok.is(tok::eof)) // Nothing to do here, bail out...
return ANK_Error;
}
Tok.setKind(tok::annot_typename);
@@ -1770,6 +1772,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
NewEndLoc);
if (NewType.isUsable())
Ty = NewType.get();
else if (Tok.is(tok::eof)) // Nothing to do here, bail out...
return false;
}
// This is a typename. Replace the current token in-place with an

View File

@@ -0,0 +1,40 @@
// RUN: %clang_cc1 -DFIRST -fsyntax-only -verify %s
// RUN: %clang_cc1 -DSECOND -fsyntax-only -verify %s
// RUN: %clang_cc1 -DTHIRD -fsyntax-only -verify %s
// RUN: %clang_cc1 -DFOURTH -fsyntax-only -verify %s
@protocol P;
@interface NSObject
@end
@protocol X
@end
@interface X : NSObject <X>
@end
@class A;
#ifdef FIRST
id<X> F1(id<[P> v) { // expected-error {{expected a type}} // expected-error {{use of undeclared identifier 'P'}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}}
return 0;
}
#endif
#ifdef SECOND
id<X> F2(id<P[X> v) { // expected-error {{unknown type name 'P'}} // expected-error {{unexpected interface name 'X': expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}}
return 0;
}
#endif
#ifdef THIRD
id<X> F3(id<P, P *[> v) { // expected-error {{unknown type name 'P'}} // expected-error {{expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}}
return 0;
}
#endif
#ifdef FOURTH
id<X> F4(id<P, P *(> v { // expected-error {{unknown type name 'P'}} // expected-error {{expected ')'}} // expected-note {{to match this '('}} // expected-note {{to match this '('}}
return 0;
}
#endif
// expected-error {{expected '>'}} // expected-error {{expected parameter declarator}} // expected-error {{expected ')'}} // expected-error {{expected function body after function declarator}}