From 2ebb178f8bebbc55e2d1496997ac3e4de4289f95 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 23 Aug 2008 01:48:03 +0000 Subject: [PATCH] Fix a FIXME by not creating an invalid AST on erroneous input. Also make diagnostic output in some other malformed cases significantly more useful. This fixes PR2708 llvm-svn: 55215 --- clang/include/clang/Basic/DiagnosticKinds.def | 8 +++-- clang/lib/Parse/ParseObjc.cpp | 34 +++++++++++++------ clang/test/SemaObjC/method-def-1.m | 13 ++++++- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 82f927db607f..7e1ccc7f259e 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -322,8 +322,8 @@ DIAG(err_parse_error, ERROR, "parse error") DIAG(err_expected_expression, ERROR, "expected expression") -DIAG(err_invalid_receiver_to_message, ERROR, - "invalid receiver to message expression") +DIAG(err_expected_type, ERROR, + "expected a type") DIAG(err_expected_external_declaration, ERROR, "expected external declaration") DIAG(err_expected_ident, ERROR, @@ -386,6 +386,8 @@ DIAG(err_expected_string_literal, ERROR, "expected string literal") DIAG(err_expected_asm_operand, ERROR, "expected string literal or '[' for asm operand") +DIAG(err_expected_selector_for_method, ERROR, + "expected selector for Objective-C method") DIAG(err_unexpected_at, ERROR, "unexpected '@' in program") @@ -409,6 +411,8 @@ DIAG(warn_objc_protocol_qualifier_missing_id, WARNING, DIAG(warn_objc_array_of_interfaces, WARNING, "array of interface '%0' should probably be an array of pointers") +DIAG(err_invalid_receiver_to_message, ERROR, + "invalid receiver to message expression") DIAG(err_objc_illegal_visibility_spec, ERROR, "illegal visibility specification") DIAG(err_objc_illegal_interface_qual, ERROR, diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 007970190bf3..31e62d343454 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -561,6 +561,7 @@ Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { assert(Tok.is(tok::l_paren) && "expected ("); SourceLocation LParenLoc = ConsumeParen(), RParenLoc; + SourceLocation TypeStartLoc = Tok.getLocation(); TypeTy *Ty = 0; // Parse type qualifiers, in, inout, etc. @@ -571,9 +572,17 @@ Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { // FIXME: back when Sema support is in place... // assert(Ty && "Parser::ParseObjCTypeName(): missing type"); } + if (Tok.isNot(tok::r_paren)) { - MatchRHSPunctuation(tok::r_paren, LParenLoc); - return 0; // FIXME: decide how we want to handle this error... + // If we didn't eat any tokens, then this isn't a type. + if (Tok.getLocation() == TypeStartLoc) { + Diag(Tok.getLocation(), diag::err_expected_type); + SkipUntil(tok::r_brace); + } else { + // Otherwise, we found *something*, but didn't get a ')' in the right + // place. Emit an error then return what we have as the type. + MatchRHSPunctuation(tok::r_paren, LParenLoc); + } } RParenLoc = ConsumeParen(); return Ty; @@ -612,20 +621,24 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(SourceLocation mLoc, DeclTy *IDecl, tok::ObjCKeywordKind MethodImplKind) { - // Parse the return type. + // Parse the return type if present. TypeTy *ReturnType = 0; ObjCDeclSpec DSRet; if (Tok.is(tok::l_paren)) ReturnType = ParseObjCTypeName(DSRet); + SourceLocation selLoc; IdentifierInfo *SelIdent = ParseObjCSelector(selLoc); + + if (!SelIdent) { // missing selector name. + Diag(Tok.getLocation(), diag::err_expected_selector_for_method, + SourceRange(mLoc, Tok.getLocation())); + // Skip until we get a ; or {}. + SkipUntil(tok::r_brace); + return 0; + } + if (Tok.isNot(tok::colon)) { - if (!SelIdent) { - Diag(Tok, diag::err_expected_ident); // missing selector name. - // FIXME: this creates a unary selector with a null identifier, is this - // ok?? Maybe we should skip to the next semicolon or something. - } - // If attributes exist after the method, parse them. AttributeList *MethodAttrs = 0; if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) @@ -653,9 +666,8 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(SourceLocation mLoc, } ConsumeToken(); // Eat the ':'. ObjCDeclSpec DSType; - if (Tok.is(tok::l_paren)) { // Parse the argument type. + if (Tok.is(tok::l_paren)) // Parse the argument type. TypeInfo = ParseObjCTypeName(DSType); - } else TypeInfo = 0; KeyTypes.push_back(TypeInfo); diff --git a/clang/test/SemaObjC/method-def-1.m b/clang/test/SemaObjC/method-def-1.m index 2d5f92fcbc1e..c1cd6294b7e3 100644 --- a/clang/test/SemaObjC/method-def-1.m +++ b/clang/test/SemaObjC/method-def-1.m @@ -1,4 +1,4 @@ -// RUN: clang -fsyntax-only %s +// RUN: clang -fsyntax-only -verify %s @interface foo - (int)meth; @@ -8,3 +8,14 @@ - (int) meth { return [self meth]; } @end +// PR2708 +@interface MyClass ++- (void)myMethod; // expected-error {{expected selector for Objective-C method}} +- (vid)myMethod2; // expected-error {{expected a type}} +@end + +@implementation MyClass +- (void)myMethod { } +- (void)myMethod2 { } +@end +