From: Dodji Seketeli Date: Fri, 11 Jul 2008 16:32:29 +0000 (+0000) Subject: re PR c++/31754 (Improve column number accuracy in error messages) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=760b18ad400092ea513d159b825b3617247dce8c;p=gcc.git re PR c++/31754 (Improve column number accuracy in error messages) 2008-07-11 Dodji Seketeli PR c++/31754 * cp-tree.h (struct cp_decl_specifier_seq): add a location field. It carries the location of the primary type. * parser.c (cp_parser_check_type_definition): update documentation. (cp_parser_check_for_definition_in_return_type, cp_parser_check_for_invalid_template_id, cp_parser_set_decl_spec_type, cp_parser_check_for_definition_in_return_type, cp_parser_diagnose_invalid_type_name, cp_parser_new_expression, cp_parser_explicit_instantiation, cp_parser_type_specifier, cp_parser_simple_type_specifier, cp_parser_omp_for_loop, cp_parser_pragma): use location in error messages. From-SVN: r137721 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0161f2e8c10..c48fe96cb2f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,4 +1,19 @@ -2008-07-11 Dodji Seketeli +2008-07-11 Dodji Seketeli + + PR c++/31754 + * cp-tree.h (struct cp_decl_specifier_seq): add a location field. It + carries the location of the primary type. + * parser.c (cp_parser_check_type_definition): update documentation. + (cp_parser_check_for_definition_in_return_type, + cp_parser_check_for_invalid_template_id, + cp_parser_set_decl_spec_type, + cp_parser_check_for_definition_in_return_type, + cp_parser_diagnose_invalid_type_name, + cp_parser_new_expression, cp_parser_explicit_instantiation, + cp_parser_type_specifier, cp_parser_simple_type_specifier, + cp_parser_omp_for_loop, cp_parser_pragma): use location in error messages. + +2008-06-30 Dodji Seketeli PR c++/31754 * pt.c, semantic.c: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 10eba33ea3e..b07effead05 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3927,6 +3927,9 @@ typedef struct cp_decl_specifier_seq { reflected here. This field will be a TYPE, unless a typedef-name was used, in which case it will be a TYPE_DECL. */ tree type; + /* The location of the primary type. Mainly used for error + reporting. */ + location_t type_location; /* The attributes, if any, provided with the specifier sequence. */ tree attributes; /* If non-NULL, a built-in type that the user attempted to redefine diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 2429bfc20a8..567f04eea96 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1950,7 +1950,7 @@ static bool cp_parser_declares_only_class_p static void cp_parser_set_storage_class (cp_parser *, cp_decl_specifier_seq *, enum rid, location_t); static void cp_parser_set_decl_spec_type - (cp_decl_specifier_seq *, tree, bool); + (cp_decl_specifier_seq *, tree, location_t, bool); static bool cp_parser_friend_p (const cp_decl_specifier_seq *); static cp_token *cp_parser_require @@ -1998,9 +1998,9 @@ static bool cp_parser_simulate_error static bool cp_parser_check_type_definition (cp_parser *); static void cp_parser_check_for_definition_in_return_type - (cp_declarator *, tree); + (cp_declarator *, tree, location_t type_location); static void cp_parser_check_for_invalid_template_id - (cp_parser *, tree); + (cp_parser *, tree, location_t location); static bool cp_parser_non_integral_constant_expression (cp_parser *, const char *); static void cp_parser_diagnose_invalid_type_name @@ -2214,11 +2214,12 @@ cp_parser_check_type_definition (cp_parser* parser) /* This function is called when the DECLARATOR is processed. The TYPE was a type defined in the decl-specifiers. If it is invalid to define a type in the decl-specifiers for DECLARATOR, an error is - issued. */ + issued. TYPE_LOCATION is the location of TYPE and is used + for error reporting. */ static void cp_parser_check_for_definition_in_return_type (cp_declarator *declarator, - tree type) + tree type, location_t type_location) { /* [dcl.fct] forbids type definitions in return types. Unfortunately, it's not easy to know whether or not we are @@ -2231,31 +2232,32 @@ cp_parser_check_for_definition_in_return_type (cp_declarator *declarator, if (declarator && declarator->kind == cdk_function) { - error ("new types may not be defined in a return type"); - inform ("(perhaps a semicolon is missing after the definition of %qT)", - type); + error ("%Hnew types may not be defined in a return type", &type_location); + inform ("%H(perhaps a semicolon is missing after the definition of %qT)", + &type_location, type); } } /* A type-specifier (TYPE) has been parsed which cannot be followed by "<" in any valid C++ program. If the next token is indeed "<", issue a message warning the user about what appears to be an - invalid attempt to form a template-id. */ + invalid attempt to form a template-id. LOCATION is the location + of the type-specifier (TYPE) */ static void cp_parser_check_for_invalid_template_id (cp_parser* parser, - tree type) + tree type, location_t location) { cp_token_position start = 0; if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)) { if (TYPE_P (type)) - error ("%qT is not a template", type); + error ("%H%qT is not a template", &location, type); else if (TREE_CODE (type) == IDENTIFIER_NODE) - error ("%qE is not a template", type); + error ("%H%qE is not a template", &location, type); else - error ("invalid template-id"); + error ("%Hinvalid template-id", &location); /* Remember the location of the invalid "<". */ if (cp_parser_uncommitted_to_tentative_parse_p (parser)) start = cp_lexer_token_position (parser->lexer, true); @@ -2301,32 +2303,34 @@ cp_parser_non_integral_constant_expression (cp_parser *parser, qualifying scope (or NULL, if none) for ID. This function commits to the current active tentative parse, if any. (Otherwise, the problematic construct might be encountered again later, resulting - in duplicate error messages.) */ + in duplicate error messages.) LOCATION is the location of ID. */ static void cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id, - location_t id_location) + location_t location) { tree decl, old_scope; /* Try to lookup the identifier. */ old_scope = parser->scope; parser->scope = scope; - decl = cp_parser_lookup_name_simple (parser, id, id_location); + decl = cp_parser_lookup_name_simple (parser, id, location); parser->scope = old_scope; /* If the lookup found a template-name, it means that the user forgot to specify an argument list. Emit a useful error message. */ if (TREE_CODE (decl) == TEMPLATE_DECL) - error ("invalid use of template-name %qE without an argument list", decl); + error ("%Hinvalid use of template-name %qE without an argument list", + &location, decl); else if (TREE_CODE (id) == BIT_NOT_EXPR) - error ("invalid use of destructor %qD as a type", id); + error ("%Hinvalid use of destructor %qD as a type", &location, id); else if (TREE_CODE (decl) == TYPE_DECL) /* Something like 'unsigned A a;' */ - error ("invalid combination of multiple type-specifiers"); + error ("%Hinvalid combination of multiple type-specifiers", + &location); else if (!parser->scope) { /* Issue an error message. */ - error ("%qE does not name a type", id); + error ("%H%qE does not name a type", &location, id); /* If we're in a template class, it's possible that the user was referring to a type from a base class. For example: @@ -2358,8 +2362,8 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, if (TREE_CODE (field) == TYPE_DECL && DECL_NAME (field) == id) { - inform ("(perhaps % was intended)", - BINFO_TYPE (b), id); + inform ("%H(perhaps % was intended)", + &location, BINFO_TYPE (b), id); break; } if (field) @@ -2373,10 +2377,11 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, else if (parser->scope != error_mark_node) { if (TREE_CODE (parser->scope) == NAMESPACE_DECL) - error ("%qE in namespace %qE does not name a type", - id, parser->scope); + error ("%H%qE in namespace %qE does not name a type", + &location, id, parser->scope); else if (TYPE_P (parser->scope)) - error ("%qE in class %qT does not name a type", id, parser->scope); + error ("%H%qE in class %qT does not name a type", + &location, id, parser->scope); else gcc_unreachable (); } @@ -5576,7 +5581,8 @@ cp_parser_new_expression (cp_parser* parser) { error ("%Harray bound forbidden after parenthesized type-id", &token->location); - inform ("try removing the parentheses around the type-id"); + inform ("%Htry removing the parentheses around the type-id", + &token->location); cp_parser_direct_new_declarator (parser); } nelts = NULL_TREE; @@ -10599,6 +10605,7 @@ cp_parser_explicit_instantiation (cp_parser* parser) int declares_class_or_enum; cp_decl_specifier_seq decl_specifiers; tree extension_specifier = NULL_TREE; + cp_token *token; /* Look for an (optional) storage-class-specifier or function-specifier. */ @@ -10621,6 +10628,7 @@ cp_parser_explicit_instantiation (cp_parser* parser) control while processing explicit instantiation directives. */ push_deferring_access_checks (dk_no_check); /* Parse a decl-specifier-seq. */ + token = cp_lexer_peek_token (parser->lexer); cp_parser_decl_specifier_seq (parser, CP_PARSER_FLAGS_OPTIONAL, &decl_specifiers, @@ -10653,7 +10661,8 @@ cp_parser_explicit_instantiation (cp_parser* parser) /*member_p=*/false); if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, - decl_specifiers.type); + decl_specifiers.type, + decl_specifiers.type_location); if (declarator != cp_error_declarator) { decl = grokdeclarator (declarator, &decl_specifiers, @@ -10825,6 +10834,7 @@ cp_parser_type_specifier (cp_parser* parser, if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type_spec, + token->location, /*user_defined_p=*/true); return type_spec; } @@ -10849,6 +10859,7 @@ cp_parser_type_specifier (cp_parser* parser, if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type_spec, + token->location, /*user_defined_p=*/true); return type_spec; } @@ -10870,6 +10881,7 @@ cp_parser_type_specifier (cp_parser* parser, if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type_spec, + token->location, /*user_defined_p=*/true); return type_spec; @@ -11045,6 +11057,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type, + token->location, /*user_defined_p=*/true); return type; @@ -11060,6 +11073,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type, + token->location, /*user_defined_p=*/true); return type; @@ -11081,6 +11095,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, && token->keyword != RID_LONG)) cp_parser_set_decl_spec_type (decl_specs, type, + token->location, /*user_defined=*/false); if (decl_specs) decl_specs->any_specifiers_p = true; @@ -11091,7 +11106,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, /* There is no valid C++ program where a non-template type is followed by a "<". That usually indicates that the user thought that the type was a template. */ - cp_parser_check_for_invalid_template_id (parser, type); + cp_parser_check_for_invalid_template_id (parser, type, token->location); return TYPE_NAME (type); } @@ -11120,6 +11135,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, /*type_p=*/false, /*is_declaration=*/false) != NULL_TREE); + token = cp_lexer_peek_token (parser->lexer); /* If we have seen a nested-name-specifier, and the next token is `template', then we are using the template-id production. */ if (parser->scope @@ -11154,6 +11170,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, type = NULL_TREE; if (type && decl_specs) cp_parser_set_decl_spec_type (decl_specs, type, + token->location, /*user_defined=*/true); } @@ -11186,7 +11203,8 @@ cp_parser_simple_type_specifier (cp_parser* parser, return qual_type; } - cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type)); + cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type), + token->location); } return type; @@ -11608,7 +11626,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, /* A "<" cannot follow an elaborated type specifier. If that happens, the user was probably trying to form a template-id. */ - cp_parser_check_for_invalid_template_id (parser, type); + cp_parser_check_for_invalid_template_id (parser, type, token->location); return type; } @@ -12413,7 +12431,8 @@ cp_parser_init_declarator (cp_parser* parser, if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, - decl_specifiers->type); + decl_specifiers->type, + decl_specifiers->type_location); /* Figure out what scope the entity declared by the DECLARATOR is located in. `grokdeclarator' sometimes changes the scope, so @@ -14875,6 +14894,7 @@ cp_parser_class_head (cp_parser* parser, if (!cp_parser_parse_definitely (parser)) { invalid_nested_name_p = true; + type_start_token = cp_lexer_peek_token (parser->lexer); id = cp_parser_identifier (parser); if (id == error_mark_node) id = NULL_TREE; @@ -14918,7 +14938,10 @@ cp_parser_class_head (cp_parser* parser, if (!cp_parser_parse_definitely (parser)) { if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) - id = cp_parser_identifier (parser); + { + type_start_token = cp_lexer_peek_token (parser->lexer); + id = cp_parser_identifier (parser); + } else id = NULL_TREE; } @@ -14932,7 +14955,8 @@ cp_parser_class_head (cp_parser* parser, pop_deferring_access_checks (); if (id) - cp_parser_check_for_invalid_template_id (parser, id); + cp_parser_check_for_invalid_template_id (parser, id, + type_start_token->location); /* If it's not a `:' or a `{' then we can't really be looking at a class-head, since a class-head only appears as part of a @@ -15521,7 +15545,8 @@ cp_parser_member_declaration (cp_parser* parser) if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type - (declarator, decl_specifiers.type); + (declarator, decl_specifiers.type, + decl_specifiers.type_location); /* Look for an asm-specification. */ asm_specification = cp_parser_asm_specification_opt (parser); @@ -18141,6 +18166,7 @@ cp_parser_set_storage_class (cp_parser *parser, static void cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs, tree type_spec, + location_t location, bool user_defined_p) { decl_specs->any_specifiers_p = true; @@ -18167,6 +18193,7 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs, { decl_specs->type = type_spec; decl_specs->user_defined_type_p = false; + decl_specs->type_location = location; } } else if (decl_specs->type) @@ -18176,6 +18203,7 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs, decl_specs->type = type_spec; decl_specs->user_defined_type_p = user_defined_p; decl_specs->redefined_builtin_type = NULL_TREE; + decl_specs->type_location = location; } } @@ -21105,7 +21133,10 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) else { if (!collapse_err) - error ("collapsed loops not perfectly nested"); + { + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + error ("%Hcollapsed loops not perfectly nested", &loc); + } collapse_err = true; cp_parser_statement_seq_opt (parser, NULL); cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>"); @@ -21593,8 +21624,9 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) cp_parser_omp_taskwait (parser, pragma_tok); return false; case pragma_stmt: - error ("%<#pragma omp taskwait%> may only be " - "used in compound statements"); + error ("%H%<#pragma omp taskwait%> may only be " + "used in compound statements", + &pragma_tok->location); break; default: goto bad_stmt; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c558bb675a8..9833a0f828e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,16 @@ 2008-07-11 Dodji Seketeli - * g++.dg/parse/constructor1.C, g++.dg/parse/error*.C: update these + * g++.dg/other/semicolon.C: Tighten this test, making it column aware. + * g++.dg/parse/error15.C: update this because of more accurate column + numbers in error reporting. + * g++.old-deja/g++.brendan/crash16.C: Tighten the test, making it + column aware. + * g++.old-deja/g++.law/ctors5.C: Likewise. + * g++.old-deja/g++.other/crash25.C: Likewise. + +2008-06-30 Dodji Seketeli + + * g++.dg/parse/constructor1.C, g++.dg/parse/error*.C: Update these tests to make them catch column number regressions. Make these tests run with the -fshow-column option. * g++.dg/parse/error-column.C: new column number test. diff --git a/gcc/testsuite/g++.dg/other/semicolon.C b/gcc/testsuite/g++.dg/other/semicolon.C index 6bc3d95217b..542d3b7b554 100644 --- a/gcc/testsuite/g++.dg/other/semicolon.C +++ b/gcc/testsuite/g++.dg/other/semicolon.C @@ -1,9 +1,10 @@ // PR c++/18368 // Origin: Chris Lattner // { dg-do compile } +// { dg-options "-fshow-column" } struct A { - struct B { int i; } - void foo(); // { dg-error "two or more|return type" } -}; // { dg-error "semicolon is missing" "" { target *-*-* } 8 } + struct B { int i; } // { dg-error "3: error: new types may not be defined in a return type|note: \\(perhaps a semicolon is missing" } + void foo(); // { dg-error "12: error: two or more|return type" } +}; diff --git a/gcc/testsuite/g++.dg/parse/error15.C b/gcc/testsuite/g++.dg/parse/error15.C index b65175cfc91..5903a585e97 100644 --- a/gcc/testsuite/g++.dg/parse/error15.C +++ b/gcc/testsuite/g++.dg/parse/error15.C @@ -10,28 +10,28 @@ namespace N int K; } -N::A f2; // { dg-error "4: error: invalid use of template-name 'N::A' without an argument list" } -N::INVALID f3; // { dg-error "4: error: 'INVALID' in namespace 'N' does not name a type" } -N::C::INVALID f4; // { dg-error "7: error: 'INVALID' in class 'N::C' does not name a type" } -N::K f6; // { dg-error "4: error: 'K' in namespace 'N' does not name a type" } +N::A f2; // { dg-error "1: error: invalid use of template-name 'N::A' without an argument list" } +N::INVALID f3; // { dg-error "1: error: 'INVALID' in namespace 'N' does not name a type" } +N::C::INVALID f4; // { dg-error "1: error: 'INVALID' in class 'N::C' does not name a type" } +N::K f6; // { dg-error "1: error: 'K' in namespace 'N' does not name a type" } typename N::A f7; // { dg-error "1: error: using 'typename' outside of template|13: error: invalid use of template-name 'N::A' without an argument list|17: error: invalid type in declaration before ';' token" } struct B { - N::A f2; // { dg-error "6: error: invalid use of template-name 'N::A' without an argument list" } - N::INVALID f3; // { dg-error "6: error: 'INVALID' in namespace 'N' does not name a type" } - N::C::INVALID f4; // { dg-error "9: error: 'INVALID' in class 'N::C' does not name a type" } - N::K f6; // { dg-error "6: error: 'K' in namespace 'N' does not name a type" } + N::A f2; // { dg-error "3: error: invalid use of template-name 'N::A' without an argument list" } + N::INVALID f3; // { dg-error "3: error: 'INVALID' in namespace 'N' does not name a type" } + N::C::INVALID f4; // { dg-error "3: error: 'INVALID' in class 'N::C' does not name a type" } + N::K f6; // { dg-error "3: error: 'K' in namespace 'N' does not name a type" } typename N::A f7; // { dg-error "3: error: using 'typename' outside of template|15: error: invalid use of template-name 'N::A' without an argument list" } }; template struct C { - N::A f2; // { dg-error "6: error: invalid use of template-name 'N::A' without an argument list" } - N::INVALID f3; // { dg-error "6: error: 'INVALID' in namespace 'N' does not name a type" } - N::C::INVALID f4; // { dg-error "9: error: 'INVALID' in class 'N::C' does not name a type" } - N::K f6; // { dg-error "6: error: 'K' in namespace 'N' does not name a type" } + N::A f2; // { dg-error "3: error: invalid use of template-name 'N::A' without an argument list" } + N::INVALID f3; // { dg-error "3: error: 'INVALID' in namespace 'N' does not name a type" } + N::C::INVALID f4; // { dg-error "3: error: 'INVALID' in class 'N::C' does not name a type" } + N::K f6; // { dg-error "3: error: 'K' in namespace 'N' does not name a type" } typename N::A f7; // { dg-error "15: error: invalid use of template-name 'N::A' without an argument list" } }; diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash16.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash16.C index 7151eb13618..ddcae3c97cb 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/crash16.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash16.C @@ -1,12 +1,14 @@ // { dg-do compile } +// { dg-options "-fshow-column" } // GROUPS passed old-abort -class Graph { + +class Graph { // { dg-error "1: error: new types|1: note: \\(perhaps" } public: unsigned char N; - Graph(void) {} // { dg-error "previously defined here" } + Graph(void) {} // { dg-error "17: error: 'Graph" } } -Graph::Graph(void) // { dg-error "return type|redefinition|semicolon" } +Graph::Graph(void) // { dg-error "18: error: return type|18: error: redefinition" } { N = 10; } diff --git a/gcc/testsuite/g++.old-deja/g++.law/ctors5.C b/gcc/testsuite/g++.old-deja/g++.law/ctors5.C index 334b59781b1..1f469cf5d49 100644 --- a/gcc/testsuite/g++.old-deja/g++.law/ctors5.C +++ b/gcc/testsuite/g++.old-deja/g++.law/ctors5.C @@ -1,11 +1,12 @@ // { dg-do assemble } +// { dg-options "-fshow-column" } // GROUPS passed constructors // ctors file // Subject: bug in handling static const object of the enclosing class // Date: Tue, 1 Sep 92 10:38:44 EDT class X -{ // { dg-error "X::X" } implicit constructor +{ // { dg-error "1: note: X::X\\(const X&\\)" } implicit constructor private: int x; public: @@ -13,21 +14,21 @@ class X X( int ); }; -class Y +class Y // { dg-error "1: error: new types may not be defined in a return type|1: note: \\(perhaps a semicolon is missing after the definition of 'Y'\\)" } { private: X xx; public: Y(); } -X::X( int xi ) // { dg-error "return type|X::X|semicolon" } +X::X( int xi ) // { dg-error "14: error: return type specification for constructor invalid|14: note: candidates are: X::X\\(int\\)" } { x = xi; } const X X::x0( 0 ); -Y::Y() // { dg-error "no match" } +Y::Y() // { dg-error "6: error: no matching function for call to 'X::X\\(\\)'" } { xx = X::x0; } diff --git a/gcc/testsuite/g++.old-deja/g++.other/crash25.C b/gcc/testsuite/g++.old-deja/g++.other/crash25.C index b8417e8512e..517bac2d5d6 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/crash25.C +++ b/gcc/testsuite/g++.old-deja/g++.other/crash25.C @@ -1,16 +1,17 @@ // { dg-do assemble } +// { dg-options "-fshow-column" } // Origin: Jakub Jelinek -class X { +class X { // { dg-error "1: error: new types may not be defined in a return type|1: note: \\(perhaps a semicolon is missing after the definition of 'X'\\)" } public: X(); virtual ~X(); } -X::x() // { dg-error "return type|member function|semicolon" } +X::x() // { dg-error "6: error: no 'X X::x\\(\\)' member function declared in class 'X'" } { } -X::~x() // { dg-error "expected class-name" } +X::~x() // { dg-error "6: error: expected class-name before '\\(' token" } { }