diff mbox series

Capture source location of dtors (PR c++/89390)

Message ID 1550605495-27345-1-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series Capture source location of dtors (PR c++/89390) | expand

Commit Message

David Malcolm Feb. 19, 2019, 7:44 p.m. UTC
On Mon, 2019-02-18 at 14:07 -1000, Jason Merrill wrote:
> On 2/18/19 12:50 PM, Jakub Jelinek wrote:
> > Hi!
> > 
> > On the following testcase we ICE because name is BIT_NOT_EXPR and
> > suggest_alternative_in_scoped_enum assumes it is called on
> > IDENTIFIER_NODE
> > only.
> > 
> > Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-
> > linux, ok for
> > trunk?
> 
> OK.
> 
> > There is another issue, starting with 7.x we don't use sensible
> > location in
> > the diagnostics, 6.x emitted
> > pr89390.C: In function ‘void foo()’:
> > pr89390.C:9:3: error: ‘~A’ is not a member of ‘A’
> >     A::~A (); // { dg-error "'~A' is not a member of 'A'" }
> >     ^
> > but 7.x and later emits:
> > In function ‘void foo()’:
> > cc1plus: error: ‘~A’ is not a member of ‘A’
> > 
> > This patch doesn't deal with that, but would be nice to provide
> > location,
> > dunno if it is enough to just use location of ~, or if we need to
> > spend
> > memory and build ~A as combined range with caret on ~.

It should only cost memory if strlen(A) is > 30, since otherwise the
result will have caret==start and strlen() <= 31 and so hit the
optimized range representation.

> 
> I think having a range for a destructor id-expression would be
> appropriate.
> 
> Jason

How about something like this? (on top of Jakub's patch)

pr89390.C: In function 'void foo()':
pr89390.C:9:6: error: '~A' is not a member of 'A'
    9 |   A::~A ();    // { dg-error "6: '~A' is not a member of 'A'" }
      |      ^~
pr89390.C: In function 'void test_2()':
pr89390.C:17:10: error: '~ns::P' is not a member of 'ns::P'
   17 |   ns::P::~P ();    // { dg-error "10: '~ns::P' is not a member of 'ns::P'" }
      |          ^~

(Presumably gcc 10 material at this point; not yet bootstrapped).

gcc/cp/ChangeLog:
	PR c++/89390
	* parser.c (cp_parser_unqualified_id): Capture locations for
	destructors.

gcc/testsuite/ChangeLog:
	PR c++/89390
	* g++.dg/diagnostic/pr89390.C: Update expected location of error.
	Add testcase within namespace.
---
 gcc/cp/parser.c                           |  9 ++++++++-
 gcc/testsuite/g++.dg/diagnostic/pr89390.C | 10 +++++++++-
 2 files changed, 17 insertions(+), 2 deletions(-)

Comments

Jakub Jelinek Feb. 19, 2019, 7:37 p.m. UTC | #1
On Tue, Feb 19, 2019 at 02:44:55PM -0500, David Malcolm wrote:
> How about something like this? (on top of Jakub's patch)

I had following queued for regtest, so if you want to go for the
make_location ^~, you should change more spots.

> pr89390.C: In function 'void foo()':
> pr89390.C:9:6: error: '~A' is not a member of 'A'
>     9 |   A::~A ();    // { dg-error "6: '~A' is not a member of 'A'" }
>       |      ^~
> pr89390.C: In function 'void test_2()':
> pr89390.C:17:10: error: '~ns::P' is not a member of 'ns::P'
>    17 |   ns::P::~P ();    // { dg-error "10: '~ns::P' is not a member of 'ns::P'" }
>       |          ^~
> 
> (Presumably gcc 10 material at this point; not yet bootstrapped).

I wouldn't say so, it actually is even a regression:
$ /usr/src/gcc-6/obj/gcc/cc1plus -quiet pr89390.C 
pr89390.C: In function ‘void foo()’:
pr89390.C:9:3: error: ‘~A’ is not a member of ‘A’
   A::~A (); // { dg-error "'~A' is not a member of 'A'" }
   ^

$ /usr/src/gcc-7/obj/gcc/cc1plus -quiet pr89390.C 
In function ‘void foo()’:
cc1plus: error: ‘~A’ is not a member of ‘A’

Feel free to take this over though.

2019-02-19  Jakub Jelinek  <jakub@redhat.com>

	PR c++/89390
	* parser.c (cp_parser_unqualified_id): For BIT_NOT_EXPR remember
	location of the ~ token and use it to build cp_expr.

	* g++.dg/diagnostic/pr89390.C (foo): Expect diagnostics at the right
	line.

--- gcc/cp/parser.c.jj	2019-02-18 20:48:37.669649863 +0100
+++ gcc/cp/parser.c	2019-02-19 10:41:14.090972524 +0100
@@ -5976,6 +5976,7 @@ cp_parser_unqualified_id (cp_parser* par
 	tree object_scope;
 	tree scope;
 	bool done;
+	location_t loc = token->location;
 
 	/* Consume the `~' token.  */
 	cp_lexer_consume_token (parser->lexer);
@@ -6050,7 +6051,7 @@ cp_parser_unqualified_id (cp_parser* par
 		    && constructor_name_p (token->u.value, scope))))
 	  {
 	    cp_lexer_consume_token (parser->lexer);
-	    return build_nt (BIT_NOT_EXPR, scope);
+	    return cp_expr (build_nt (BIT_NOT_EXPR, scope), loc);
 	  }
 
 	/* ~auto means the destructor of whatever the object is.  */
@@ -6061,7 +6062,7 @@ cp_parser_unqualified_id (cp_parser* par
 		       "%<~auto%> only available with "
 		       "-std=c++14 or -std=gnu++14");
 	    cp_lexer_consume_token (parser->lexer);
-	    return build_nt (BIT_NOT_EXPR, make_auto ());
+	    return cp_expr (build_nt (BIT_NOT_EXPR, make_auto ()), loc);
 	  }
 
 	/* If there was an explicit qualification (S::~T), first look
@@ -6152,7 +6153,7 @@ cp_parser_unqualified_id (cp_parser* par
 		type_decl = cp_parser_identifier (parser);
 		if (type_decl != error_mark_node)
 		  type_decl = build_nt (BIT_NOT_EXPR, type_decl);
-		return type_decl;
+		return cp_expr (type_decl, loc);
 	      }
 	  }
 	/* If an error occurred, assume that the name of the
@@ -6187,7 +6188,7 @@ cp_parser_unqualified_id (cp_parser* par
 		    "typedef-name %qD used as destructor declarator",
 		    type_decl);
 
-	return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+	return cp_expr (build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl)), loc);
       }
 
     case CPP_KEYWORD:
--- gcc/testsuite/g++.dg/diagnostic/pr89390.C.jj	2019-02-19 09:38:21.816096390 +0100
+++ gcc/testsuite/g++.dg/diagnostic/pr89390.C	2019-02-19 10:41:58.867234266 +0100
@@ -6,5 +6,5 @@ enum class A { B, C };
 void
 foo ()
 {
-  A::~A ();	// { dg-error "'~A' is not a member of 'A'" "" { target *-*-* } 0 }
+  A::~A ();	// { dg-error "'~A' is not a member of 'A'" }
 }


	Jakub
David Malcolm Feb. 20, 2019, 6:26 p.m. UTC | #2
On Tue, 2019-02-19 at 20:37 +0100, Jakub Jelinek wrote:
> On Tue, Feb 19, 2019 at 02:44:55PM -0500, David Malcolm wrote:
> > How about something like this? (on top of Jakub's patch)
> 
> I had following queued for regtest, so if you want to go for the
> make_location ^~, you should change more spots.
> 
> > pr89390.C: In function 'void foo()':
> > pr89390.C:9:6: error: '~A' is not a member of 'A'
> >     9 |   A::~A ();    // { dg-error "6: '~A' is not a member of
> > 'A'" }
> >       |      ^~
> > pr89390.C: In function 'void test_2()':
> > pr89390.C:17:10: error: '~ns::P' is not a member of 'ns::P'
> >    17 |   ns::P::~P ();    // { dg-error "10: '~ns::P' is not a
> > member of 'ns::P'" }
> >       |          ^~
> > 
> > (Presumably gcc 10 material at this point; not yet bootstrapped).
> 
> I wouldn't say so, it actually is even a regression:
> $ /usr/src/gcc-6/obj/gcc/cc1plus -quiet pr89390.C 
> pr89390.C: In function ‘void foo()’:
> pr89390.C:9:3: error: ‘~A’ is not a member of ‘A’
>    A::~A (); // { dg-error "'~A' is not a member of 'A'" }
>    ^
> 
> $ /usr/src/gcc-7/obj/gcc/cc1plus -quiet pr89390.C 
> In function ‘void foo()’:
> cc1plus: error: ‘~A’ is not a member of ‘A’
> 
> Feel free to take this over though.

Sorry about colliding here; I have no objections to your version of the
patch (and yours seems more comprehensive).

Dave
diff mbox series

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ffecce4..e6fdb34 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5976,6 +5976,7 @@  cp_parser_unqualified_id (cp_parser* parser,
 	tree object_scope;
 	tree scope;
 	bool done;
+	location_t tilde_loc = token->location;
 
 	/* Consume the `~' token.  */
 	cp_lexer_consume_token (parser->lexer);
@@ -6049,8 +6050,14 @@  cp_parser_unqualified_id (cp_parser* parser,
 		|| (CLASS_TYPE_P (scope)
 		    && constructor_name_p (token->u.value, scope))))
 	  {
+	    /* Create a location with caret == start at the tilde,
+	       finishing at the end of the peeked token, e.g:
+	         ~class_name
+		 ^~~~~~~~~~~.  */
+	    location_t loc
+	      = make_location (tilde_loc, tilde_loc, token->location);
 	    cp_lexer_consume_token (parser->lexer);
-	    return build_nt (BIT_NOT_EXPR, scope);
+	    return cp_expr (build_nt (BIT_NOT_EXPR, scope), loc);
 	  }
 
 	/* ~auto means the destructor of whatever the object is.  */
diff --git a/gcc/testsuite/g++.dg/diagnostic/pr89390.C b/gcc/testsuite/g++.dg/diagnostic/pr89390.C
index df35fcc..91a6422 100644
--- a/gcc/testsuite/g++.dg/diagnostic/pr89390.C
+++ b/gcc/testsuite/g++.dg/diagnostic/pr89390.C
@@ -6,5 +6,13 @@  enum class A { B, C };
 void
 foo ()
 {
-  A::~A ();    // { dg-error "'~A' is not a member of 'A'" "" { target *-*-* } 0 }
+  A::~A ();    // { dg-error "6: '~A' is not a member of 'A'" }
+}
+
+namespace ns { enum class P { Q, R }; }
+
+void
+test_2 ()
+{
+  ns::P::~P ();    // { dg-error "10: '~ns::P' is not a member of 'ns::P'" }
 }