[gcc r16-3509] tree-cfg: Fix up assign_discriminator ICE with too large #line [PR121663]

Jakub Jelinek jakub@gcc.gnu.org
Tue Sep 2 10:21:51 GMT 2025


https://gcc.gnu.org/g:5440f4ceee3152148c6c212f57b85da918b66abf

commit r16-3509-g5440f4ceee3152148c6c212f57b85da918b66abf
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Sep 2 12:18:52 2025 +0200

    tree-cfg: Fix up assign_discriminator ICE with too large #line [PR121663]
    
    As mentioned in the PR, LOCATION_LINE is represented in an int,
    and while we have -pedantic diagnostics (and -pedantic-error error)
    for too large #line, we can still overflow into negative line
    numbers up to -2 and -1.  We could overflow to that even with valid
    source if it says has #line 2147483640 and then just has
    2G+ lines after it.
    Now, the ICE is because assign_discriminator{,s} uses a hash_map
    with int_hash <int64_t, -1, -2>, so values -2 and -1 are reserved
    for deleted and empty entries.  We just need to make sure those aren't
    valid.  One possible fix would be just that
    -  discrim_entry &e = map.get_or_insert (LOCATION_LINE (loc), &existed);
    +  discrim_entry &e
    +    = map.get_or_insert ((unsigned) LOCATION_LINE (loc), &existed);
    by adding unsigned cast when the key is signed 64-bit, it will never
    be -1 or -2.
    But I think that is wasteful, discrim_entry is a struct with 2 unsigned
    non-static data members, so for lines which can only be 0 to 0xffffffff
    (sure, with wrap-around), I think just using a hash_map with 96bit elts
    is better than 128bit.
    So, the following patch just doesn't assign any discriminators for lines
    -1U and -2U, I think that is fine, normal programs never do that.
    Another possibility would be to handle lines -1U and -2U as if it was say
    -3U.
    
    2025-09-02  Jakub Jelinek  <jakub@redhat.com>
    
            PR middle-end/121663
            * tree-cfg.cc (assign_discriminator): Change map argument type
            from hash_map with int_hash <int64_t, -1, -2> to one with
            int_hash <unsigned, -1U, -2U>.  Cast LOCATION_LINE to unsigned.
            Return early for (unsigned) LOCATION_LINE above -3U.
            (assign_discriminators): Change map type from hash_map with
            int_hash <int64_t, -1, -2> to one with int_hash <unsigned, -1U, -2U>.
    
            * gcc.dg/pr121663.c: New test.

Diff:
---
 gcc/testsuite/gcc.dg/pr121663.c |  9 +++++++++
 gcc/tree-cfg.cc                 | 10 +++++++---
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/pr121663.c b/gcc/testsuite/gcc.dg/pr121663.c
new file mode 100644
index 000000000000..b1dfa302c2aa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr121663.c
@@ -0,0 +1,9 @@
+/* PR middle-end/121663 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void
+foo (void)
+{
+#line 4294967295
+}
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index 4c885637da3a..c3883446de8b 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -1095,10 +1095,14 @@ struct discrim_entry
 
 location_t
 assign_discriminator (location_t loc, unsigned int bb_id,
-		      hash_map<int_hash <int64_t, -1, -2>, discrim_entry> &map)
+		      hash_map<int_hash <unsigned, -1U, -2U>,
+			       discrim_entry> &map)
 {
   bool existed;
-  discrim_entry &e = map.get_or_insert (LOCATION_LINE (loc), &existed);
+  if ((unsigned) LOCATION_LINE (loc) >= -2U)
+    return loc;
+  discrim_entry &e
+    = map.get_or_insert ((unsigned) LOCATION_LINE (loc), &existed);
   gcc_checking_assert (!has_discriminator (loc));
   if (!existed)
     {
@@ -1121,7 +1125,7 @@ assign_discriminator (location_t loc, unsigned int bb_id,
 static void
 assign_discriminators (void)
 {
-  hash_map<int_hash <int64_t, -1, -2>, discrim_entry> map (13);
+  hash_map<int_hash <unsigned, -1U, -2U>, discrim_entry> map (13);
   unsigned int bb_id = 0;
   basic_block bb;
   FOR_EACH_BB_FN (bb, cfun)


More information about the Gcc-cvs mailing list