[flang-commits] [flang] [flang] Reorder messages wrt line number before diff(actual, expect) (PR #186812)

Krzysztof Parzyszek via flang-commits flang-commits at lists.llvm.org
Mon Mar 16 08:25:21 PDT 2026


https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/186812

>From 466dba8948313acebe744024750ba973257ddef4 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 16 Mar 2026 09:28:02 -0500
Subject: [PATCH 1/4] [flang] Reorder messages wrt line number before
 diff(actual, expect)

When messages are attached together, the source locations to which they
refer are not necessarily monotonically increasing. For example
```
error: foo.f90:10: There is a problem here         # line 10
because: foo.f90:12: This thing is invalid         # line 12 (attached)
error: foo.f90:11: There is another problem here   # line 11
```
There is no way to represent that in the source flle via ERROR annotations,
so before running unified_diff "canonicalize" the list of messages into an
order that corresponds to the line numbers.
---
 flang/test/Semantics/test_errors.py | 55 +++++++++++++++++++++++++----
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/flang/test/Semantics/test_errors.py b/flang/test/Semantics/test_errors.py
index 45684764a00e4..95d974954b7d1 100755
--- a/flang/test/Semantics/test_errors.py
+++ b/flang/test/Semantics/test_errors.py
@@ -15,12 +15,46 @@
 
 from difflib import unified_diff
 
+# When messages are attached together, the source locations to which they
+# refer are not necessarily monotonically increasing. For example
+#   error: foo.f90:10: There is a problem here         # line 10
+#   because: foo.f90:12: This thing is invalid         # line 12 (attached)
+#   error: foo.f90:11: There is another problem here   # line 11
+# There is no way to represent that in the source flle via ERROR annotations,
+# so before running unified_diff "canonicalize" the list of messages into an
+# order that corresponds to the line numbers.
+#
+# This also eliminates the issue with multiple messages emitted for the same
+# line: they can now be "expected" in the test file in any order, e.g.
+#   !ERROR: Not enough arguments in a call to foo
+#   !ERROR: `foo` is a subroutine, not a function
+#   a = foo()
+# has the same effect as:
+#   !ERROR: `foo` is a subroutine, not a function
+#   !ERROR: Not enough arguments in a call to foo
+#   a = foo()
+
+
+def join_per_line_map(m):
+    """Take a map {"line_no:": [message1, message2, ...], ...} and convert
+    it into a newline-separated string that follows the line ordering.
+    """
+    # Sort messages for each line, and prepend the line number to each
+    # message. Use numeric values of line numbers as keys to allow them
+    # to be sorted numerically.
+    sorted_lines_map = {
+        int(k.rstrip(":")): [k + s for s in sorted(m[k])] for k in m.keys()
+    }
+
+    joined_lines_list = []
+    for line in sorted(sorted_lines_map.keys()):
+        joined_lines_list.append("\n".join(sorted_lines_map[line]))
+    return "\n".join(joined_lines_list)
+
 cm.check_args(sys.argv)
 srcdir = cm.set_source(sys.argv[1])
 with open(srcdir, "r", encoding="utf-8") as f:
     src = f.readlines()
-actual = ""
-expect = ""
 diffs = ""
 log = ""
 
@@ -48,14 +82,21 @@
             sys.exit(1)
 
 # Cleans up the output from the compilation process to be easier to process
+actual_per_line = dict()
 for line in log.split("\n"):
-    m = re.search(r"[^:]*:(\d+:).*(?:error|warning|portability|because):(.*)", line)
+    m = re.search(
+        r"[^:]*:(\d+:).*(?:error|warning|portability|because):(.*)", line
+    )
     if m:
         if re.search(r"warning: .*fold.*host", line):
             continue  # ignore host-dependent folding warnings
-        actual += m.expand(r"\1\2\n")
+        line_colon = m.expand(r"\1")
+        actual_per_line[line_colon] = actual_per_line.get(line_colon, []) + [
+            m.expand(r"\2")
+        ]
 
 # Gets the expected errors and their line numbers
+expect_per_line = dict()
 errors = []
 for i, line in enumerate(src, 1):
     m = re.search(r"(?:^\s*!\s*(?:ERROR|WARNING|PORTABILITY|BECAUSE): )(.*)", line)
@@ -63,10 +104,12 @@
         errors.append(m.group(1))
         continue
     if errors:
-        for x in errors:
-            expect += f"{i}: {x}\n"
+        expect_per_line[f"{i}:"] = [f" {x}" for x in errors]
         errors = []
 
+actual = join_per_line_map(actual_per_line)
+expect = join_per_line_map(expect_per_line)
+
 # Compares the expected errors with the compiler errors
 for line in unified_diff(actual.split("\n"), expect.split("\n"), n=0):
     line = re.sub(r"(^\-)(\d+:)", r"\nactual at \g<2>", line)

>From 08328800d338239114e73462205c5ded6dcc50c6 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 16 Mar 2026 09:50:55 -0500
Subject: [PATCH 2/4] format

---
 flang/test/Semantics/test_errors.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/flang/test/Semantics/test_errors.py b/flang/test/Semantics/test_errors.py
index 95d974954b7d1..7d2382f676c61 100755
--- a/flang/test/Semantics/test_errors.py
+++ b/flang/test/Semantics/test_errors.py
@@ -84,9 +84,7 @@ def join_per_line_map(m):
 # Cleans up the output from the compilation process to be easier to process
 actual_per_line = dict()
 for line in log.split("\n"):
-    m = re.search(
-        r"[^:]*:(\d+:).*(?:error|warning|portability|because):(.*)", line
-    )
+    m = re.search(r"[^:]*:(\d+:).*(?:error|warning|portability|because):(.*)", line)
     if m:
         if re.search(r"warning: .*fold.*host", line):
             continue  # ignore host-dependent folding warnings

>From 603e2046e879621552735b64f98a1b9f76ed0008 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 16 Mar 2026 09:53:34 -0500
Subject: [PATCH 3/4] format

---
 flang/test/Semantics/test_errors.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/flang/test/Semantics/test_errors.py b/flang/test/Semantics/test_errors.py
index 7d2382f676c61..c14762b604fd3 100755
--- a/flang/test/Semantics/test_errors.py
+++ b/flang/test/Semantics/test_errors.py
@@ -51,6 +51,7 @@ def join_per_line_map(m):
         joined_lines_list.append("\n".join(sorted_lines_map[line]))
     return "\n".join(joined_lines_list)
 
+
 cm.check_args(sys.argv)
 srcdir = cm.set_source(sys.argv[1])
 with open(srcdir, "r", encoding="utf-8") as f:

>From 268fe255d639e4c648bd9e746552ef319b297525 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 16 Mar 2026 10:25:10 -0500
Subject: [PATCH 4/4] Update flang/test/Semantics/test_errors.py

Co-authored-by: Michael Kruse <llvm-project at meinersbur.de>
---
 flang/test/Semantics/test_errors.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang/test/Semantics/test_errors.py b/flang/test/Semantics/test_errors.py
index c14762b604fd3..05ae6b8309de6 100755
--- a/flang/test/Semantics/test_errors.py
+++ b/flang/test/Semantics/test_errors.py
@@ -20,7 +20,7 @@
 #   error: foo.f90:10: There is a problem here         # line 10
 #   because: foo.f90:12: This thing is invalid         # line 12 (attached)
 #   error: foo.f90:11: There is another problem here   # line 11
-# There is no way to represent that in the source flle via ERROR annotations,
+# There is no way to represent that in the source file via ERROR annotations,
 # so before running unified_diff "canonicalize" the list of messages into an
 # order that corresponds to the line numbers.
 #



More information about the flang-commits mailing list