c++: Member initializer list diagnostic locations [PR94024]
authorPatrick Palka <ppalka@redhat.com>
Tue, 4 Aug 2020 14:11:35 +0000 (10:11 -0400)
committerPatrick Palka <ppalka@redhat.com>
Tue, 4 Aug 2020 14:11:35 +0000 (10:11 -0400)
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.

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
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/diagnostic/mem-init1.C [new file with mode: 0644]

index cb9bd2d..3f08940 100644 (file)
@@ -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);
index ab08887..7657145 100644 (file)
@@ -15411,7 +15411,20 @@ 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.  */
+  location_t loc
+    = make_location (token->location, token->location, parser->lexer);
+  tree dummy = build0 (EMPTY_CLASS_EXPR, NULL_TREE);
+  SET_EXPR_LOCATION (dummy, loc);
+  TREE_TYPE (node) = dummy;
+
+  return node;
 }
 
 /* Parse a mem-initializer-id.
index bd2af8b..cff2db4 100644 (file)
@@ -26018,6 +26018,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 (file)
index 0000000..b749c72
--- /dev/null
@@ -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;