From 134c192bb33f87fc0b261b32d4e18a497c1e1b1c Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Sat, 6 Nov 2010 18:41:57 +0000 Subject: [PATCH] re PR c++/45332 (Generate clear diagnostics when a terminating semicolon is missing from a class member declaration.) gcc/cp/ PR c++/45332 * parser.c (cp_lexer_previous_token): New function. (cp_parser_member_declaration): Use previous token for error messages. Assume semicolon presence rather than grovelling for the next one. gcc/testsuite/ PR c++/45332 * g++.dg/parse/semicolon2.C: New testcase. * g++.dg/ext/asmspec1.C: Adjust. * g++.dg/init/new13.C: Adjust. * g++.dg/parse/ctor5.C: Adjust. From-SVN: r166406 --- gcc/cp/ChangeLog | 8 ++++++ gcc/cp/parser.c | 33 ++++++++++++++++++++++--- gcc/testsuite/ChangeLog | 8 ++++++ gcc/testsuite/g++.dg/ext/asmspec1.C | 4 +-- gcc/testsuite/g++.dg/init/new13.C | 4 +-- gcc/testsuite/g++.dg/parse/ctor5.C | 6 ++--- gcc/testsuite/g++.dg/parse/semicolon2.C | 9 +++++++ 7 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/semicolon2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bfa4af43916..784f3aab15d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2010-11-06 Nathan Froyd + + PR c++/45332 + * parser.c (cp_lexer_previous_token): New function. + (cp_parser_member_declaration): Use previous token for error + messages. Assume semicolon presence rather than grovelling for + the next one. + 2010-11-06 Joern Rennecke PR middle-end/46314 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6302864fd97..6a9e4d7b981 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -502,6 +502,19 @@ cp_lexer_token_at (cp_lexer *lexer ATTRIBUTE_UNUSED, cp_token_position pos) return pos; } +static inline cp_token * +cp_lexer_previous_token (cp_lexer *lexer) +{ + cp_token_position tp; + + if (lexer->next_token == &eof_token) + tp = lexer->last_token - 1; + else + tp = cp_lexer_token_position (lexer, true); + + return cp_lexer_token_at (lexer, tp); +} + /* nonzero if we are presently saving tokens. */ static inline int @@ -17627,6 +17640,8 @@ cp_parser_member_declaration (cp_parser* parser) } else { + bool assume_semicolon = false; + /* See if these declarations will be friends. */ friend_p = cp_parser_friend_p (&decl_specifiers); @@ -17820,11 +17835,18 @@ cp_parser_member_declaration (cp_parser* parser) else if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { - cp_parser_error (parser, "expected %<;%>"); - /* Skip tokens until we find a `;'. */ - cp_parser_skip_to_end_of_statement (parser); + /* The next token might be a ways away from where the + actual semicolon is missing. Find the previous token + and use that for our error position. */ + cp_token *token = cp_lexer_previous_token (parser->lexer); + error_at (token->location, + "expected %<;%> at end of member declaration"); - break; + /* Assume that the user meant to provide a semicolon. If + we were to cp_parser_skip_to_end_of_statement, we might + skip to a semicolon inside a member function definition + and issue nonsensical error messages. */ + assume_semicolon = true; } if (decl) @@ -17836,6 +17858,9 @@ cp_parser_member_declaration (cp_parser* parser) if (TREE_CODE (decl) == FUNCTION_DECL) cp_parser_save_default_args (parser, decl); } + + if (assume_semicolon) + return; } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4577eb26dfa..911ba143162 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2010-11-06 Nathan Froyd + + PR c++/45332 + * g++.dg/parse/semicolon2.C: New testcase. + * g++.dg/ext/asmspec1.C: Adjust. + * g++.dg/init/new13.C: Adjust. + * g++.dg/parse/ctor5.C: Adjust. + 2010-11-06 Janus Weil PR fortran/46330 diff --git a/gcc/testsuite/g++.dg/ext/asmspec1.C b/gcc/testsuite/g++.dg/ext/asmspec1.C index 3df2483ad53..0661136fecc 100644 --- a/gcc/testsuite/g++.dg/ext/asmspec1.C +++ b/gcc/testsuite/g++.dg/ext/asmspec1.C @@ -3,6 +3,6 @@ struct A { - int i __asm__(int); // { dg-error "before" } - static int j __asm__(int); // { dg-error "before" } + int i __asm__(int); // { dg-error "expected" } + static int j __asm__(int); // { dg-error "expected" } }; diff --git a/gcc/testsuite/g++.dg/init/new13.C b/gcc/testsuite/g++.dg/init/new13.C index 3563c48808f..2ced6e3fe02 100644 --- a/gcc/testsuite/g++.dg/init/new13.C +++ b/gcc/testsuite/g++.dg/init/new13.C @@ -5,7 +5,7 @@ struct A { - void* operator new(__SIZE_TYPE__) throw(X); // { dg-error "" } + void* operator new(__SIZE_TYPE__) throw(X); // { dg-error "expected|type" } }; -A* p = new A; // { dg-error "no suitable" } +A* p = new A; diff --git a/gcc/testsuite/g++.dg/parse/ctor5.C b/gcc/testsuite/g++.dg/parse/ctor5.C index 819458598a3..3ea23549c0b 100644 --- a/gcc/testsuite/g++.dg/parse/ctor5.C +++ b/gcc/testsuite/g++.dg/parse/ctor5.C @@ -2,9 +2,9 @@ struct A { - int i; - A() i() {} // { dg-error "expected" } -}; // { dg-error "expected" } + int i; // { dg-error "conflicts" } + A() i() {} // { dg-error "declaration" } +}; struct B { diff --git a/gcc/testsuite/g++.dg/parse/semicolon2.C b/gcc/testsuite/g++.dg/parse/semicolon2.C new file mode 100644 index 00000000000..d14a225a674 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/semicolon2.C @@ -0,0 +1,9 @@ +// PR c++/45332 +// { dg-do compile } + +class C +{ + int x // { dg-error "at end of member declaration" } + + const int foo() { return x; } +};