diff mbox series

c++: Member initializer list diagnostic locations [PR94024]

Message ID 20200803141451.867700-1-ppalka@redhat.com
State New
Headers show
Series c++: Member initializer list diagnostic locations [PR94024] | expand

Commit Message

Patrick Palka Aug. 3, 2020, 2:14 p.m. UTC
This patch preserves the source locations of each node in a member
initializer list so that during processing of the list we can set
input_location appropriately for generally more accurate diagnostic
locations.  Since TREE_LIST nodes are tcc_exceptional, they can't have
source locations, so we instead store the location in a dummy
tcc_expression node within the TREE_TYPE of the list node.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
commit?

gcc/cp/ChangeLog:

	PR c++/94024
	* init.c (sort_mem_initializers): Preserve TREE_TYPE of the
	member initializer list node.
	(emit_mem_initializers): Set input_location when performing each
	member initialization.
	* parser.c (cp_parser_mem_initializer_list): Attach the source
	location of this initializer to a dummy EMPTY_CLASS_EXPR within
	the TREE_TYPE of the list node.
	* pt.c (tsubst_initializer_list): Preserve TREE_TYPE of the
	member initializer list node.

gcc/testsuite/ChangeLog:

	PR c++/94024
	* g++.dg/diagnostic/mem-init1.C: New test.
---
 gcc/cp/init.c                               |  6 +++++
 gcc/cp/parser.c                             |  8 ++++++
 gcc/cp/pt.c                                 |  3 +++
 gcc/testsuite/g++.dg/diagnostic/mem-init1.C | 29 +++++++++++++++++++++
 4 files changed, 46 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/mem-init1.C

Comments

Jason Merrill Aug. 3, 2020, 3:17 p.m. UTC | #1
On 8/3/20 10:14 AM, Patrick Palka wrote:
> This patch preserves the source locations of each node in a member
> initializer list so that during processing of the list we can set
> input_location appropriately for generally more accurate diagnostic
> locations.  Since TREE_LIST nodes are tcc_exceptional, they can't have
> source locations, so we instead store the location in a dummy
> tcc_expression node within the TREE_TYPE of the list node.

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
> commit?
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/94024
> 	* init.c (sort_mem_initializers): Preserve TREE_TYPE of the
> 	member initializer list node.
> 	(emit_mem_initializers): Set input_location when performing each
> 	member initialization.
> 	* parser.c (cp_parser_mem_initializer_list): Attach the source
> 	location of this initializer to a dummy EMPTY_CLASS_EXPR within
> 	the TREE_TYPE of the list node.
> 	* pt.c (tsubst_initializer_list): Preserve TREE_TYPE of the
> 	member initializer list node.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/94024
> 	* g++.dg/diagnostic/mem-init1.C: New test.
> ---
>   gcc/cp/init.c                               |  6 +++++
>   gcc/cp/parser.c                             |  8 ++++++
>   gcc/cp/pt.c                                 |  3 +++
>   gcc/testsuite/g++.dg/diagnostic/mem-init1.C | 29 +++++++++++++++++++++
>   4 files changed, 46 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/diagnostic/mem-init1.C
> 
> diff --git a/gcc/cp/init.c b/gcc/cp/init.c
> index cb9bd2dbfba..3f089404cf2 100644
> --- a/gcc/cp/init.c
> +++ b/gcc/cp/init.c
> @@ -1151,6 +1151,8 @@ sort_mem_initializers (tree t, tree mem_inits)
>   
>         /* Record the initialization.  */
>         TREE_VALUE (subobject_init) = TREE_VALUE (init);
> +      /* Carry over the dummy TREE_TYPE node containing the source location.  */
> +      TREE_TYPE (subobject_init) = TREE_TYPE (init);
>         next_subobject = subobject_init;
>       }
>   
> @@ -1367,6 +1369,10 @@ emit_mem_initializers (tree mem_inits)
>     /* Initialize the data members.  */
>     while (mem_inits)
>       {
> +      /* If this initializer was explicitly provided, then the dummy TREE_TYPE
> +	 node contains the source location.  */
> +      iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits)));
> +
>         perform_member_init (TREE_PURPOSE (mem_inits),
>   			   TREE_VALUE (mem_inits));
>         mem_inits = TREE_CHAIN (mem_inits);
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index ab088874ba7..2f9b8786121 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -15326,6 +15326,14 @@ cp_parser_mem_initializer_list (cp_parser* parser)
>   	{
>   	  TREE_CHAIN (mem_initializer) = mem_initializer_list;
>   	  mem_initializer_list = mem_initializer;
> +
> +	  /* We can't attach the source location of this initializer directly to
> +	     the list node, so we instead attach it to a dummy EMPTY_CLASS_EXPR
> +	     within the TREE_TYPE of the list node.  */
> +	  TREE_TYPE (mem_initializer) = build0 (EMPTY_CLASS_EXPR, NULL_TREE);
> +	  SET_EXPR_LOCATION (TREE_TYPE (mem_initializer),
> +			     make_location (token->location,
> +					    token->location, input_location));

Why not do this in cp_parser_mem_initializer?

Also, use parser->lexer for the last argument to make_location.

>   	}
>         /* If the next token is not a `,', we're done.  */
>         if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 3a168d506cf..bed1a3532e7 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -26014,6 +26014,9 @@ tsubst_initializer_list (tree t, tree argvec)
>             if (decl)
>               {
>                 init = build_tree_list (decl, init);
> +	      /* Carry over the dummy TREE_TYPE node containing the source
> +		 location.  */
> +	      TREE_TYPE (init) = TREE_TYPE (t);
>                 TREE_CHAIN (init) = inits;
>                 inits = init;
>               }
> diff --git a/gcc/testsuite/g++.dg/diagnostic/mem-init1.C b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C
> new file mode 100644
> index 00000000000..b749c72cd8b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C
> @@ -0,0 +1,29 @@
> +// PR c++/94024
> +// { dg-do compile }
> +
> +struct A {
> +    A()
> +    : a()       // { dg-error "reference type" }
> +    , b(1)      // { dg-error "incompatible" }
> +    , c(0)      // { dg-bogus "" }
> +    {}
> +
> +    int &a;
> +    int b[1];
> +    char c;
> +};
> +
> +template<typename T, typename U>
> +struct B {
> +    B()
> +    : a()       // { dg-error "reference type" }
> +    , b(1)      // { dg-error "incompatible" }
> +    , c(0)      // { dg-bogus "" }
> +    {}
> +
> +    T a;
> +    U b;
> +    char c;
> +};
> +
> +B<int&, int[1]> b;
>
Patrick Palka Aug. 3, 2020, 6:49 p.m. UTC | #2
On Mon, 3 Aug 2020, Jason Merrill wrote:

> On 8/3/20 10:14 AM, Patrick Palka wrote:
> > This patch preserves the source locations of each node in a member
> > initializer list so that during processing of the list we can set
> > input_location appropriately for generally more accurate diagnostic
> > locations.  Since TREE_LIST nodes are tcc_exceptional, they can't have
> > source locations, so we instead store the location in a dummy
> > tcc_expression node within the TREE_TYPE of the list node.
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
> > commit?
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	PR c++/94024
> > 	* init.c (sort_mem_initializers): Preserve TREE_TYPE of the
> > 	member initializer list node.
> > 	(emit_mem_initializers): Set input_location when performing each
> > 	member initialization.
> > 	* parser.c (cp_parser_mem_initializer_list): Attach the source
> > 	location of this initializer to a dummy EMPTY_CLASS_EXPR within
> > 	the TREE_TYPE of the list node.
> > 	* pt.c (tsubst_initializer_list): Preserve TREE_TYPE of the
> > 	member initializer list node.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	PR c++/94024
> > 	* g++.dg/diagnostic/mem-init1.C: New test.
> > ---
> >   gcc/cp/init.c                               |  6 +++++
> >   gcc/cp/parser.c                             |  8 ++++++
> >   gcc/cp/pt.c                                 |  3 +++
> >   gcc/testsuite/g++.dg/diagnostic/mem-init1.C | 29 +++++++++++++++++++++
> >   4 files changed, 46 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/diagnostic/mem-init1.C
> > 
> > diff --git a/gcc/cp/init.c b/gcc/cp/init.c
> > index cb9bd2dbfba..3f089404cf2 100644
> > --- a/gcc/cp/init.c
> > +++ b/gcc/cp/init.c
> > @@ -1151,6 +1151,8 @@ sort_mem_initializers (tree t, tree mem_inits)
> >           /* Record the initialization.  */
> >         TREE_VALUE (subobject_init) = TREE_VALUE (init);
> > +      /* Carry over the dummy TREE_TYPE node containing the source
> > location.  */
> > +      TREE_TYPE (subobject_init) = TREE_TYPE (init);
> >         next_subobject = subobject_init;
> >       }
> >   @@ -1367,6 +1369,10 @@ emit_mem_initializers (tree mem_inits)
> >     /* Initialize the data members.  */
> >     while (mem_inits)
> >       {
> > +      /* If this initializer was explicitly provided, then the dummy
> > TREE_TYPE
> > +	 node contains the source location.  */
> > +      iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits)));
> > +
> >         perform_member_init (TREE_PURPOSE (mem_inits),
> >   			   TREE_VALUE (mem_inits));
> >         mem_inits = TREE_CHAIN (mem_inits);
> > diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> > index ab088874ba7..2f9b8786121 100644
> > --- a/gcc/cp/parser.c
> > +++ b/gcc/cp/parser.c
> > @@ -15326,6 +15326,14 @@ cp_parser_mem_initializer_list (cp_parser* parser)
> >   	{
> >   	  TREE_CHAIN (mem_initializer) = mem_initializer_list;
> >   	  mem_initializer_list = mem_initializer;
> > +
> > +	  /* We can't attach the source location of this initializer directly
> > to
> > +	     the list node, so we instead attach it to a dummy
> > EMPTY_CLASS_EXPR
> > +	     within the TREE_TYPE of the list node.  */
> > +	  TREE_TYPE (mem_initializer) = build0 (EMPTY_CLASS_EXPR, NULL_TREE);
> > +	  SET_EXPR_LOCATION (TREE_TYPE (mem_initializer),
> > +			     make_location (token->location,
> > +					    token->location, input_location));
> 
> Why not do this in cp_parser_mem_initializer?
> 
> Also, use parser->lexer for the last argument to make_location.

That's a much better spot for it :) Done and done.  Does the following
look OK after testing completes?

-- >8 --

Subject: [PATCH] c++: Member initializer list diagnostic locations [PR94024]

This patch preserves the source locations of each node in a member
initializer list so that during processing of the list we can set
input_location appropriately for generally more accurate diagnostic
locations.  Since TREE_LIST nodes are tcc_exceptional, they can't have
source locations, so we instead store the location in a dummy
tcc_expression node within the TREE_TYPE of the list node.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
commit?

gcc/cp/ChangeLog:

	PR c++/94024
	* init.c (sort_mem_initializers): Preserve TREE_TYPE of the
	member initializer list node.
	(emit_mem_initializers): Set input_location when performing each
	member initialization.
	* parser.c (cp_parser_mem_initializer): Attach the source
	location of this initializer to a dummy EMPTY_CLASS_EXPR
	within the TREE_TYPE of the list node.
	* pt.c (tsubst_initializer_list): Preserve TREE_TYPE of the
	member initializer list node.

gcc/testsuite/ChangeLog:

	PR c++/94024
	* g++.dg/diagnostic/mem-init1.C: New test.
---
 gcc/cp/init.c                               |  6 +++++
 gcc/cp/parser.c                             | 13 ++++++++-
 gcc/cp/pt.c                                 |  3 +++
 gcc/testsuite/g++.dg/diagnostic/mem-init1.C | 29 +++++++++++++++++++++
 4 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/mem-init1.C

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index cb9bd2dbfba..3f089404cf2 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1151,6 +1151,8 @@ sort_mem_initializers (tree t, tree mem_inits)
 
       /* Record the initialization.  */
       TREE_VALUE (subobject_init) = TREE_VALUE (init);
+      /* Carry over the dummy TREE_TYPE node containing the source location.  */
+      TREE_TYPE (subobject_init) = TREE_TYPE (init);
       next_subobject = subobject_init;
     }
 
@@ -1367,6 +1369,10 @@ emit_mem_initializers (tree mem_inits)
   /* Initialize the data members.  */
   while (mem_inits)
     {
+      /* If this initializer was explicitly provided, then the dummy TREE_TYPE
+	 node contains the source location.  */
+      iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits)));
+
       perform_member_init (TREE_PURPOSE (mem_inits),
 			   TREE_VALUE (mem_inits));
       mem_inits = TREE_CHAIN (mem_inits);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ab088874ba7..8b11e478c83 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -15411,7 +15411,18 @@ cp_parser_mem_initializer (cp_parser* parser)
 
   in_base_initializer = 0;
 
-  return member ? build_tree_list (member, expression_list) : error_mark_node;
+  if (!member)
+    return error_mark_node;
+
+  tree node = build_tree_list (member, expression_list);
+  /* We can't attach the source location of this initializer directly to
+     the list node, so we instead attach it to a dummy EMPTY_CLASS_EXPR
+     within the TREE_TYPE of the list node.  */
+  TREE_TYPE (node) = build0 (EMPTY_CLASS_EXPR, NULL_TREE);
+  SET_EXPR_LOCATION (TREE_TYPE (node),
+		     make_location (token->location,
+				    token->location, parser->lexer));
+  return node;
 }
 
 /* Parse a mem-initializer-id.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 524c0bfe2d6..721eb5262d6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -26014,6 +26014,9 @@ tsubst_initializer_list (tree t, tree argvec)
           if (decl)
             {
               init = build_tree_list (decl, init);
+	      /* Carry over the dummy TREE_TYPE node containing the source
+		 location.  */
+	      TREE_TYPE (init) = TREE_TYPE (t);
               TREE_CHAIN (init) = inits;
               inits = init;
             }
diff --git a/gcc/testsuite/g++.dg/diagnostic/mem-init1.C b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C
new file mode 100644
index 00000000000..b749c72cd8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C
@@ -0,0 +1,29 @@
+// PR c++/94024
+// { dg-do compile }
+
+struct A {
+    A()
+    : a()       // { dg-error "reference type" }
+    , b(1)      // { dg-error "incompatible" }
+    , c(0)      // { dg-bogus "" }
+    {}
+
+    int &a;
+    int b[1];
+    char c;
+};
+
+template<typename T, typename U>
+struct B {
+    B()
+    : a()       // { dg-error "reference type" }
+    , b(1)      // { dg-error "incompatible" }
+    , c(0)      // { dg-bogus "" }
+    {}
+
+    T a;
+    U b;
+    char c;
+};
+
+B<int&, int[1]> b;
Jason Merrill Aug. 3, 2020, 8:10 p.m. UTC | #3
On 8/3/20 2:49 PM, Patrick Palka wrote:
> On Mon, 3 Aug 2020, Jason Merrill wrote:
> 
>> On 8/3/20 10:14 AM, Patrick Palka wrote:
>>> This patch preserves the source locations of each node in a member
>>> initializer list so that during processing of the list we can set
>>> input_location appropriately for generally more accurate diagnostic
>>> locations.  Since TREE_LIST nodes are tcc_exceptional, they can't have
>>> source locations, so we instead store the location in a dummy
>>> tcc_expression node within the TREE_TYPE of the list node.
>>
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
>>> commit?
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	PR c++/94024
>>> 	* init.c (sort_mem_initializers): Preserve TREE_TYPE of the
>>> 	member initializer list node.
>>> 	(emit_mem_initializers): Set input_location when performing each
>>> 	member initialization.
>>> 	* parser.c (cp_parser_mem_initializer_list): Attach the source
>>> 	location of this initializer to a dummy EMPTY_CLASS_EXPR within
>>> 	the TREE_TYPE of the list node.
>>> 	* pt.c (tsubst_initializer_list): Preserve TREE_TYPE of the
>>> 	member initializer list node.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 	PR c++/94024
>>> 	* g++.dg/diagnostic/mem-init1.C: New test.
>>> ---
>>>    gcc/cp/init.c                               |  6 +++++
>>>    gcc/cp/parser.c                             |  8 ++++++
>>>    gcc/cp/pt.c                                 |  3 +++
>>>    gcc/testsuite/g++.dg/diagnostic/mem-init1.C | 29 +++++++++++++++++++++
>>>    4 files changed, 46 insertions(+)
>>>    create mode 100644 gcc/testsuite/g++.dg/diagnostic/mem-init1.C
>>>
>>> diff --git a/gcc/cp/init.c b/gcc/cp/init.c
>>> index cb9bd2dbfba..3f089404cf2 100644
>>> --- a/gcc/cp/init.c
>>> +++ b/gcc/cp/init.c
>>> @@ -1151,6 +1151,8 @@ sort_mem_initializers (tree t, tree mem_inits)
>>>            /* Record the initialization.  */
>>>          TREE_VALUE (subobject_init) = TREE_VALUE (init);
>>> +      /* Carry over the dummy TREE_TYPE node containing the source
>>> location.  */
>>> +      TREE_TYPE (subobject_init) = TREE_TYPE (init);
>>>          next_subobject = subobject_init;
>>>        }
>>>    @@ -1367,6 +1369,10 @@ emit_mem_initializers (tree mem_inits)
>>>      /* Initialize the data members.  */
>>>      while (mem_inits)
>>>        {
>>> +      /* If this initializer was explicitly provided, then the dummy
>>> TREE_TYPE
>>> +	 node contains the source location.  */
>>> +      iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits)));
>>> +
>>>          perform_member_init (TREE_PURPOSE (mem_inits),
>>>    			   TREE_VALUE (mem_inits));
>>>          mem_inits = TREE_CHAIN (mem_inits);
>>> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
>>> index ab088874ba7..2f9b8786121 100644
>>> --- a/gcc/cp/parser.c
>>> +++ b/gcc/cp/parser.c
>>> @@ -15326,6 +15326,14 @@ cp_parser_mem_initializer_list (cp_parser* parser)
>>>    	{
>>>    	  TREE_CHAIN (mem_initializer) = mem_initializer_list;
>>>    	  mem_initializer_list = mem_initializer;
>>> +
>>> +	  /* We can't attach the source location of this initializer directly
>>> to
>>> +	     the list node, so we instead attach it to a dummy
>>> EMPTY_CLASS_EXPR
>>> +	     within the TREE_TYPE of the list node.  */
>>> +	  TREE_TYPE (mem_initializer) = build0 (EMPTY_CLASS_EXPR, NULL_TREE);
>>> +	  SET_EXPR_LOCATION (TREE_TYPE (mem_initializer),
>>> +			     make_location (token->location,
>>> +					    token->location, input_location));
>>
>> Why not do this in cp_parser_mem_initializer?
>>
>> Also, use parser->lexer for the last argument to make_location.
> 
> That's a much better spot for it :) Done and done.  Does the following
> look OK after testing completes?

OK.

> -- >8 --
> 
> Subject: [PATCH] c++: Member initializer list diagnostic locations [PR94024]
> 
> This patch preserves the source locations of each node in a member
> initializer list so that during processing of the list we can set
> input_location appropriately for generally more accurate diagnostic
> locations.  Since TREE_LIST nodes are tcc_exceptional, they can't have
> source locations, so we instead store the location in a dummy
> tcc_expression node within the TREE_TYPE of the list node.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
> commit?
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/94024
> 	* init.c (sort_mem_initializers): Preserve TREE_TYPE of the
> 	member initializer list node.
> 	(emit_mem_initializers): Set input_location when performing each
> 	member initialization.
> 	* parser.c (cp_parser_mem_initializer): Attach the source
> 	location of this initializer to a dummy EMPTY_CLASS_EXPR
> 	within the TREE_TYPE of the list node.
> 	* pt.c (tsubst_initializer_list): Preserve TREE_TYPE of the
> 	member initializer list node.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/94024
> 	* g++.dg/diagnostic/mem-init1.C: New test.
> ---
>   gcc/cp/init.c                               |  6 +++++
>   gcc/cp/parser.c                             | 13 ++++++++-
>   gcc/cp/pt.c                                 |  3 +++
>   gcc/testsuite/g++.dg/diagnostic/mem-init1.C | 29 +++++++++++++++++++++
>   4 files changed, 50 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/diagnostic/mem-init1.C
> 
> diff --git a/gcc/cp/init.c b/gcc/cp/init.c
> index cb9bd2dbfba..3f089404cf2 100644
> --- a/gcc/cp/init.c
> +++ b/gcc/cp/init.c
> @@ -1151,6 +1151,8 @@ sort_mem_initializers (tree t, tree mem_inits)
>   
>         /* Record the initialization.  */
>         TREE_VALUE (subobject_init) = TREE_VALUE (init);
> +      /* Carry over the dummy TREE_TYPE node containing the source location.  */
> +      TREE_TYPE (subobject_init) = TREE_TYPE (init);
>         next_subobject = subobject_init;
>       }
>   
> @@ -1367,6 +1369,10 @@ emit_mem_initializers (tree mem_inits)
>     /* Initialize the data members.  */
>     while (mem_inits)
>       {
> +      /* If this initializer was explicitly provided, then the dummy TREE_TYPE
> +	 node contains the source location.  */
> +      iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits)));
> +
>         perform_member_init (TREE_PURPOSE (mem_inits),
>   			   TREE_VALUE (mem_inits));
>         mem_inits = TREE_CHAIN (mem_inits);
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index ab088874ba7..8b11e478c83 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -15411,7 +15411,18 @@ cp_parser_mem_initializer (cp_parser* parser)
>   
>     in_base_initializer = 0;
>   
> -  return member ? build_tree_list (member, expression_list) : error_mark_node;
> +  if (!member)
> +    return error_mark_node;
> +
> +  tree node = build_tree_list (member, expression_list);
> +  /* We can't attach the source location of this initializer directly to
> +     the list node, so we instead attach it to a dummy EMPTY_CLASS_EXPR
> +     within the TREE_TYPE of the list node.  */
> +  TREE_TYPE (node) = build0 (EMPTY_CLASS_EXPR, NULL_TREE);
> +  SET_EXPR_LOCATION (TREE_TYPE (node),
> +		     make_location (token->location,
> +				    token->location, parser->lexer));
> +  return node;
>   }
>   
>   /* Parse a mem-initializer-id.
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 524c0bfe2d6..721eb5262d6 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -26014,6 +26014,9 @@ tsubst_initializer_list (tree t, tree argvec)
>             if (decl)
>               {
>                 init = build_tree_list (decl, init);
> +	      /* Carry over the dummy TREE_TYPE node containing the source
> +		 location.  */
> +	      TREE_TYPE (init) = TREE_TYPE (t);
>                 TREE_CHAIN (init) = inits;
>                 inits = init;
>               }
> diff --git a/gcc/testsuite/g++.dg/diagnostic/mem-init1.C b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C
> new file mode 100644
> index 00000000000..b749c72cd8b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C
> @@ -0,0 +1,29 @@
> +// PR c++/94024
> +// { dg-do compile }
> +
> +struct A {
> +    A()
> +    : a()       // { dg-error "reference type" }
> +    , b(1)      // { dg-error "incompatible" }
> +    , c(0)      // { dg-bogus "" }
> +    {}
> +
> +    int &a;
> +    int b[1];
> +    char c;
> +};
> +
> +template<typename T, typename U>
> +struct B {
> +    B()
> +    : a()       // { dg-error "reference type" }
> +    , b(1)      // { dg-error "incompatible" }
> +    , c(0)      // { dg-bogus "" }
> +    {}
> +
> +    T a;
> +    U b;
> +    char c;
> +};
> +
> +B<int&, int[1]> b;
>
diff mbox series

Patch

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index cb9bd2dbfba..3f089404cf2 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1151,6 +1151,8 @@  sort_mem_initializers (tree t, tree mem_inits)
 
       /* Record the initialization.  */
       TREE_VALUE (subobject_init) = TREE_VALUE (init);
+      /* Carry over the dummy TREE_TYPE node containing the source location.  */
+      TREE_TYPE (subobject_init) = TREE_TYPE (init);
       next_subobject = subobject_init;
     }
 
@@ -1367,6 +1369,10 @@  emit_mem_initializers (tree mem_inits)
   /* Initialize the data members.  */
   while (mem_inits)
     {
+      /* If this initializer was explicitly provided, then the dummy TREE_TYPE
+	 node contains the source location.  */
+      iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits)));
+
       perform_member_init (TREE_PURPOSE (mem_inits),
 			   TREE_VALUE (mem_inits));
       mem_inits = TREE_CHAIN (mem_inits);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ab088874ba7..2f9b8786121 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -15326,6 +15326,14 @@  cp_parser_mem_initializer_list (cp_parser* parser)
 	{
 	  TREE_CHAIN (mem_initializer) = mem_initializer_list;
 	  mem_initializer_list = mem_initializer;
+
+	  /* We can't attach the source location of this initializer directly to
+	     the list node, so we instead attach it to a dummy EMPTY_CLASS_EXPR
+	     within the TREE_TYPE of the list node.  */
+	  TREE_TYPE (mem_initializer) = build0 (EMPTY_CLASS_EXPR, NULL_TREE);
+	  SET_EXPR_LOCATION (TREE_TYPE (mem_initializer),
+			     make_location (token->location,
+					    token->location, input_location));
 	}
       /* If the next token is not a `,', we're done.  */
       if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3a168d506cf..bed1a3532e7 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -26014,6 +26014,9 @@  tsubst_initializer_list (tree t, tree argvec)
           if (decl)
             {
               init = build_tree_list (decl, init);
+	      /* Carry over the dummy TREE_TYPE node containing the source
+		 location.  */
+	      TREE_TYPE (init) = TREE_TYPE (t);
               TREE_CHAIN (init) = inits;
               inits = init;
             }
diff --git a/gcc/testsuite/g++.dg/diagnostic/mem-init1.C b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C
new file mode 100644
index 00000000000..b749c72cd8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C
@@ -0,0 +1,29 @@ 
+// PR c++/94024
+// { dg-do compile }
+
+struct A {
+    A()
+    : a()       // { dg-error "reference type" }
+    , b(1)      // { dg-error "incompatible" }
+    , c(0)      // { dg-bogus "" }
+    {}
+
+    int &a;
+    int b[1];
+    char c;
+};
+
+template<typename T, typename U>
+struct B {
+    B()
+    : a()       // { dg-error "reference type" }
+    , b(1)      // { dg-error "incompatible" }
+    , c(0)      // { dg-bogus "" }
+    {}
+
+    T a;
+    U b;
+    char c;
+};
+
+B<int&, int[1]> b;