xref: /llvm-project/flang/test/Semantics/test_errors.py (revision f98ee40f4b5d7474fc67e82824bf6abbaedb7b1c)
1#!/usr/bin/env python3
2
3"""Compiles a source file and checks errors against those listed in the file.
4
5Parameters:
6    sys.argv[1]: a source file with contains the input and expected output
7    sys.argv[2]: the Flang frontend driver
8    sys.argv[3:]: Optional arguments to the Flang frontend driver"""
9
10import sys
11import re
12import tempfile
13import subprocess
14import common as cm
15
16from difflib import unified_diff
17
18cm.check_args(sys.argv)
19srcdir = cm.set_source(sys.argv[1])
20with open(srcdir, "r") as f:
21    src = f.readlines()
22actual = ""
23expect = ""
24diffs = ""
25log = ""
26
27flang_fc1 = cm.set_executable(sys.argv[2])
28flang_fc1_args = sys.argv[3:]
29flang_fc1_options = "-fsyntax-only"
30
31# Compiles, and reads in the output from the compilation process
32cmd = [flang_fc1, *flang_fc1_args, flang_fc1_options, str(srcdir)]
33with tempfile.TemporaryDirectory() as tmpdir:
34    try:
35        proc = subprocess.run(
36            cmd,
37            stdout=subprocess.PIPE,
38            stderr=subprocess.PIPE,
39            check=True,
40            universal_newlines=True,
41            cwd=tmpdir,
42        )
43    except subprocess.CalledProcessError as e:
44        log = e.stderr
45        if e.returncode >= 128:
46            print(f"{log}")
47            sys.exit(1)
48
49# Cleans up the output from the compilation process to be easier to process
50for line in log.split("\n"):
51    m = re.search(r"[^:]*:(\d+:).*(?:error|warning|portability|because):(.*)", line)
52    if m:
53        if re.search(r"warning: .*fold.*host", line):
54            continue  # ignore host-dependent folding warnings
55        actual += m.expand(r"\1\2\n")
56
57# Gets the expected errors and their line numbers
58errors = []
59for i, line in enumerate(src, 1):
60    m = re.search(r"(?:^\s*!\s*(?:ERROR|WARNING|PORTABILITY|BECAUSE): )(.*)", line)
61    if m:
62        errors.append(m.group(1))
63        continue
64    if errors:
65        for x in errors:
66            expect += f"{i}: {x}\n"
67        errors = []
68
69# Compares the expected errors with the compiler errors
70for line in unified_diff(actual.split("\n"), expect.split("\n"), n=0):
71    line = re.sub(r"(^\-)(\d+:)", r"\nactual at \g<2>", line)
72    line = re.sub(r"(^\+)(\d+:)", r"\nexpect at \g<2>", line)
73    diffs += line
74
75if diffs != "":
76    print(diffs)
77    print()
78    print("FAIL")
79    sys.exit(1)
80else:
81    print()
82    print("PASS")
83