From 4e14911f373cdd45007dec06fee6ddaee5f5c9c6 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Sat, 13 Sep 2025 22:30:46 +0000 Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?= =?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.6 [skip ci] --- llvm/docs/CommandGuide/lit.rst | 1 + llvm/test/tools/llvm-cgdata/empty.test | 1 + llvm/utils/lit/lit/TestRunner.py | 20 +++++++++++++++++++ .../Inputs/shtest-readfile/absolute-paths.txt | 6 ++++++ .../lit/tests/Inputs/shtest-readfile/lit.cfg | 8 ++++++++ .../Inputs/shtest-readfile/relative-paths.txt | 7 +++++++ .../Inputs/shtest-readfile/two-same-line.txt | 8 ++++++++ llvm/utils/lit/tests/shtest-readfile.py | 17 ++++++++++++++++ 8 files changed, 68 insertions(+) create mode 100644 llvm/utils/lit/tests/Inputs/shtest-readfile/absolute-paths.txt create mode 100644 llvm/utils/lit/tests/Inputs/shtest-readfile/lit.cfg create mode 100644 llvm/utils/lit/tests/Inputs/shtest-readfile/relative-paths.txt create mode 100644 llvm/utils/lit/tests/Inputs/shtest-readfile/two-same-line.txt create mode 100644 llvm/utils/lit/tests/shtest-readfile.py diff --git a/llvm/docs/CommandGuide/lit.rst b/llvm/docs/CommandGuide/lit.rst index 15c249d8e6d31..359e0c3e81d0e 100644 --- a/llvm/docs/CommandGuide/lit.rst +++ b/llvm/docs/CommandGuide/lit.rst @@ -664,6 +664,7 @@ TestRunner.py: Otherwise, %t but with a single leading ``/`` removed. %:T On Windows, %/T but a ``:`` is removed if its the second character. Otherwise, %T but with a single leading ``/`` removed. + %{readfile:} Reads the file specified. ======================= ============== Other substitutions are provided that are variations on this base set and diff --git a/llvm/test/tools/llvm-cgdata/empty.test b/llvm/test/tools/llvm-cgdata/empty.test index 52d0dfb87623f..7e42db5ed8512 100644 --- a/llvm/test/tools/llvm-cgdata/empty.test +++ b/llvm/test/tools/llvm-cgdata/empty.test @@ -35,3 +35,4 @@ RUN: printf '\000\000\000\000' >> %t_header.cgdata RUN: printf '\040\000\000\000\000\000\000\000' >> %t_header.cgdata RUN: printf '\040\000\000\000\000\000\000\000' >> %t_header.cgdata RUN: diff %t_header.cgdata %t_emptyheader.cgdata +RUN: echo %{readfile:/tmp/test} > /tmp/test diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py index 90c2c6479b004..5daa8887e4c80 100644 --- a/llvm/utils/lit/lit/TestRunner.py +++ b/llvm/utils/lit/lit/TestRunner.py @@ -720,6 +720,23 @@ def processRedirects(cmd, stdin_source, cmd_shenv, opened_files): return std_fds +def _expandLateSubstitutions(arguments, cwd): + for i, arg in enumerate(arguments): + if not isinstance(arg, str): + continue + + def _replaceReadFile(match): + filePath = match.group(1) + if not os.path.isabs(filePath): + filePath = os.path.join(cwd, filePath) + with open(filePath) as fileHandle: + return fileHandle.read() + + arguments[i] = re.sub(r"%{readfile:([^}]*)}", _replaceReadFile, arg) + + return arguments + + def _executeShCmd(cmd, shenv, results, timeoutHelper): if timeoutHelper.timeoutReached(): # Prevent further recursion if the timeout has been hit @@ -834,6 +851,9 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper): # Ensure args[0] is hashable. args[0] = expand_glob(args[0], cmd_shenv.cwd)[0] + # Expand all late substitutions + args = _expandLateSubstitutions(args, cmd_shenv.cwd) + inproc_builtin = inproc_builtins.get(args[0], None) if inproc_builtin and (args[0] != "echo" or len(cmd.commands) == 1): # env calling an in-process builtin is useless, so we take the safe diff --git a/llvm/utils/lit/tests/Inputs/shtest-readfile/absolute-paths.txt b/llvm/utils/lit/tests/Inputs/shtest-readfile/absolute-paths.txt new file mode 100644 index 0000000000000..4246064cf7bfc --- /dev/null +++ b/llvm/utils/lit/tests/Inputs/shtest-readfile/absolute-paths.txt @@ -0,0 +1,6 @@ +## Tests that readfile works with absolute paths +# RUN: echo -n "hello" > %t +# RUN: echo %{readfile:%t} + +## Fail the test so we can assert on the output. +# RUN: not echo return diff --git a/llvm/utils/lit/tests/Inputs/shtest-readfile/lit.cfg b/llvm/utils/lit/tests/Inputs/shtest-readfile/lit.cfg new file mode 100644 index 0000000000000..25651f2cd4832 --- /dev/null +++ b/llvm/utils/lit/tests/Inputs/shtest-readfile/lit.cfg @@ -0,0 +1,8 @@ +import lit.formats + +config.name = "shtest-readfile" +config.suffixes = [".txt"] +config.test_format = lit.formats.ShTest(execute_external=False) +config.test_source_root = None +config.test_exec_root = None +config.substitutions.append(("%{python}", '"%s"' % (sys.executable))) diff --git a/llvm/utils/lit/tests/Inputs/shtest-readfile/relative-paths.txt b/llvm/utils/lit/tests/Inputs/shtest-readfile/relative-paths.txt new file mode 100644 index 0000000000000..3d203d411379d --- /dev/null +++ b/llvm/utils/lit/tests/Inputs/shtest-readfile/relative-paths.txt @@ -0,0 +1,7 @@ +## Tests that readfile works with relative paths +# RUN: mkdir -p rel_path_test_folder +# RUN: echo -n "hello" > rel_path_test_folder/test_file +# RUN: echo %{readfile:rel_path_test_folder/test_file} + +## Fail the test so we can assert on the output. +# RUN: not echo return diff --git a/llvm/utils/lit/tests/Inputs/shtest-readfile/two-same-line.txt b/llvm/utils/lit/tests/Inputs/shtest-readfile/two-same-line.txt new file mode 100644 index 0000000000000..6855d27d66d35 --- /dev/null +++ b/llvm/utils/lit/tests/Inputs/shtest-readfile/two-same-line.txt @@ -0,0 +1,8 @@ +## Tests that readfile works with two substitutions on the same line to ensure the +## regular expressions are setup correctly. +# RUN: echo -n "hello" > %t.1 +# RUN: echo -n "bye" > %t.2 +# RUN: echo %{readfile:%t.1} %{readfile:%t.2} + +## Fail the test so we can assert on the output. +# RUN: not echo return diff --git a/llvm/utils/lit/tests/shtest-readfile.py b/llvm/utils/lit/tests/shtest-readfile.py new file mode 100644 index 0000000000000..8ba8e53b32966 --- /dev/null +++ b/llvm/utils/lit/tests/shtest-readfile.py @@ -0,0 +1,17 @@ +## Tests the readfile substitution + +# RUN: not %{lit} -a -v %{inputs}/shtest-readfile | FileCheck -match-full-lines %s + +# CHECK: -- Testing: 3 tests{{.*}} + +# CHECK-LABEL: FAIL: shtest-readfile :: absolute-paths.txt ({{[^)]*}}) +# CHECK: echo hello +# CHECK: # executed command: echo '%{readfile:{{.*}}}' + +# CHECK-LABEL: FAIL: shtest-readfile :: relative-paths.txt ({{[^)]*}}) +# CHECK: echo hello +# CHECK: # executed command: echo '%{readfile:rel_path_test_folder/test_file}' + +# CHECK-LABEL: FAIL: shtest-readfile :: two-same-line.txt ({{[^)]*}}) +# CHECK: echo hello bye +# CHECK: # executed command: echo '%{readfile:{{.*}}.1}' '%{readfile:{{.*}}.2}' From 0c5c9e9092dc6d876498e72d36e3361d404fccac Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Wed, 17 Sep 2025 19:19:15 +0000 Subject: [PATCH 2/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?= =?UTF-8?q?anges=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.6 [skip ci] --- llvm/utils/lit/lit/TestRunner.py | 29 ++++++++++++++++--- .../shtest-readfile/file-does-not-exist.txt | 4 +++ .../lit/tests/Inputs/shtest-readfile/lit.cfg | 14 ++++++++- .../lit/tests/shtest-readfile-external.py | 21 ++++++++++++++ llvm/utils/lit/tests/shtest-readfile.py | 8 +++-- 5 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 llvm/utils/lit/tests/Inputs/shtest-readfile/file-does-not-exist.txt create mode 100644 llvm/utils/lit/tests/shtest-readfile-external.py diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py index 19462431e7deb..53eeb2f85b48b 100644 --- a/llvm/utils/lit/lit/TestRunner.py +++ b/llvm/utils/lit/lit/TestRunner.py @@ -720,7 +720,7 @@ def processRedirects(cmd, stdin_source, cmd_shenv, opened_files): return std_fds -def _expandLateSubstitutions(arguments, cwd): +def _expandLateSubstitutions(cmd, arguments, cwd): for i, arg in enumerate(arguments): if not isinstance(arg, str): continue @@ -729,8 +729,11 @@ def _replaceReadFile(match): filePath = match.group(1) if not os.path.isabs(filePath): filePath = os.path.join(cwd, filePath) - with open(filePath) as fileHandle: - return fileHandle.read() + try: + with open(filePath) as fileHandle: + return fileHandle.read() + except FileNotFoundError: + raise InternalShellError(cmd, "File does not exist: %s" % filePath) arguments[i] = re.sub(r"%{readfile:([^}]*)}", _replaceReadFile, arg) @@ -852,7 +855,7 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper): args[0] = expand_glob(args[0], cmd_shenv.cwd)[0] # Expand all late substitutions. - args = _expandLateSubstitutions(args, cmd_shenv.cwd) + args = _expandLateSubstitutions(j, args, cmd_shenv.cwd) inproc_builtin = inproc_builtins.get(args[0], None) if inproc_builtin and (args[0] != "echo" or len(cmd.commands) == 1): @@ -2409,6 +2412,20 @@ def runOnce( status, output, attempts=i + 1, max_allowed_attempts=attempts ) +def _expandLateSubstitutionsExternal(commandLine): + filePaths = [] + def _replaceReadFile(match): + filePath = match.group(1) + filePaths.append(filePath) + return "$(cat %s)" % filePath + + commandLine = re.sub(r"%{readfile:([^}]*)}", _replaceReadFile, commandLine) + # Add test commands before the command to check if the file exists as + # cat inside a subshell will never return a non-zero exit code outside + # of the subshell. + for filePath in filePaths: + commandLine = "%s && test -e %s" % (commandLine, filePath) + return commandLine def executeShTest( test, litConfig, useExternalSh, extra_substitutions=[], preamble_commands=[] @@ -2440,4 +2457,8 @@ def executeShTest( recursion_limit=test.config.recursiveExpansionLimit, ) + if useExternalSh: + for index, command in enumerate(script): + script[index] = _expandLateSubstitutionsExternal(command) + return _runShTest(test, litConfig, useExternalSh, script, tmpBase) diff --git a/llvm/utils/lit/tests/Inputs/shtest-readfile/file-does-not-exist.txt b/llvm/utils/lit/tests/Inputs/shtest-readfile/file-does-not-exist.txt new file mode 100644 index 0000000000000..1151b75f2fa00 --- /dev/null +++ b/llvm/utils/lit/tests/Inputs/shtest-readfile/file-does-not-exist.txt @@ -0,0 +1,4 @@ +## Test that readfile reports information appropriately when the file specified +## does not exist. + +# RUN: echo %{readfile:/file/does/not/exist} diff --git a/llvm/utils/lit/tests/Inputs/shtest-readfile/lit.cfg b/llvm/utils/lit/tests/Inputs/shtest-readfile/lit.cfg index cf453e1ea786f..ee496674fdb62 100644 --- a/llvm/utils/lit/tests/Inputs/shtest-readfile/lit.cfg +++ b/llvm/utils/lit/tests/Inputs/shtest-readfile/lit.cfg @@ -1,7 +1,19 @@ +import os + import lit.formats +import lit.util config.name = "shtest-readfile" config.suffixes = [".txt"] -config.test_format = lit.formats.ShTest(execute_external=False) +lit_shell_env = os.environ.get("LIT_USE_INTERNAL_SHELL") +use_lit_shell = lit.util.pythonize_bool(lit_shell_env) +config.test_format = lit.formats.ShTest(execute_external=not use_lit_shell) config.test_source_root = None config.test_exec_root = None + +# If we are testing with the external shell, remove the fake-externals from +# PATH so that we use mkdir in the tests. +if not use_lit_shell: + path_parts = config.environment["PATH"].split(os.path.pathsep) + path_parts = [path_part for path_part in path_parts if "fake-externals" not in path_part] + config.environment["PATH"] = os.path.pathsep.join(path_parts) diff --git a/llvm/utils/lit/tests/shtest-readfile-external.py b/llvm/utils/lit/tests/shtest-readfile-external.py new file mode 100644 index 0000000000000..5825ad674ba05 --- /dev/null +++ b/llvm/utils/lit/tests/shtest-readfile-external.py @@ -0,0 +1,21 @@ +## Tests the readfile substitution. + +# RUN: env LIT_USE_INTERNAL_SHELL=0 not %{lit} -a -v %{inputs}/shtest-readfile | FileCheck -match-full-lines -DTEMP_PATH=%S/Inputs/shtest-readfile/Output %s + +# CHECK: -- Testing: 4 tests{{.*}} + +# CHECK-LABEL: FAIL: shtest-readfile :: absolute-paths.txt ({{[^)]*}}) +# CHECK: echo $(cat [[TEMP_PATH]]/absolute-paths.txt.tmp) && test -e /home/gha/llvm-project/build/utils/lit/tests/Inputs/shtest-readfile/Output/absolute-paths.txt.tmp {{.*}} +# CHECK: + echo hello + +# CHECK-LABEL: FAIL: shtest-readfile :: file-does-not-exist.txt ({{[^)]*}}) +# CHECK: echo $(cat /file/does/not/exist) && test -e /file/does/not/exist {{.*}} +# CHECK: cat: /file/does/not/exist: No such file or directory + +# CHECK-LABEL: FAIL: shtest-readfile :: relative-paths.txt ({{[^)]*}}) +# CHECK: echo $(cat rel_path_test_folder/test_file) && test -e rel_path_test_folder/test_file {{.*}} +# CHECK: + echo hello + +# CHECK-LABEL: FAIL: shtest-readfile :: two-same-line.txt ({{[^)]*}}) +# CHECK: echo $(cat /home/gha/llvm-project/build/utils/lit/tests/Inputs/shtest-readfile/Output/two-same-line.txt.tmp.1) $(cat /home/gha/llvm-project/build/utils/lit/tests/Inputs/shtest-readfile/Output/two-same-line.txt.tmp.2) && test -e /home/gha/llvm-project/build/utils/lit/tests/Inputs/shtest-readfile/Output/two-same-line.txt.tmp.1 && test -e /home/gha/llvm-project/build/utils/lit/tests/Inputs/shtest-readfile/Output/two-same-line.txt.tmp.2 {{.*}} +# CHECK: + echo hello bye diff --git a/llvm/utils/lit/tests/shtest-readfile.py b/llvm/utils/lit/tests/shtest-readfile.py index 245ea371bc14d..2200576d05394 100644 --- a/llvm/utils/lit/tests/shtest-readfile.py +++ b/llvm/utils/lit/tests/shtest-readfile.py @@ -1,13 +1,17 @@ ## Tests the readfile substitution. -# RUN: not %{lit} -a -v %{inputs}/shtest-readfile | FileCheck -match-full-lines -DTEMP_PATH=%S/Inputs/shtest-readfile/Output %s +# RUN: env LIT_USE_INTERNAL_SHELL=1 not %{lit} -a -v %{inputs}/shtest-readfile | FileCheck -match-full-lines -DTEMP_PATH=%S/Inputs/shtest-readfile/Output %s -# CHECK: -- Testing: 3 tests{{.*}} +# CHECK: -- Testing: 4 tests{{.*}} # CHECK-LABEL: FAIL: shtest-readfile :: absolute-paths.txt ({{[^)]*}}) # CHECK: echo hello # CHECK: # executed command: echo '%{readfile:[[TEMP_PATH]]/absolute-paths.txt.tmp}' +# CHECK-LABEL: FAIL: shtest-readfile :: file-does-not-exist.txt ({{[^)]*}}) +# CHECK: # executed command: @echo 'echo %{readfile:/file/does/not/exist}' +# CHECK: # | File does not exist: /file/does/not/exist + # CHECK-LABEL: FAIL: shtest-readfile :: relative-paths.txt ({{[^)]*}}) # CHECK: echo hello # CHECK: # executed command: echo '%{readfile:rel_path_test_folder/test_file}' From 3ea0a2c82a707adde245d0aaa293c26afa84eb91 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Fri, 19 Sep 2025 23:03:05 +0000 Subject: [PATCH 3/3] fix CI Created using spr 1.3.6 --- clang/test/ClangScanDeps/pr61006.cppm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/ClangScanDeps/pr61006.cppm b/clang/test/ClangScanDeps/pr61006.cppm index f10bc1e673987..6c3783308b645 100644 --- a/clang/test/ClangScanDeps/pr61006.cppm +++ b/clang/test/ClangScanDeps/pr61006.cppm @@ -7,7 +7,7 @@ // RUN: split-file %s %t // // RUN: %clang -print-resource-dir | tr -d '\n' > %t/resource-dir -// RUN: env EXPECTED_RESOURCE_DIR=%{readfile:%t/resource-dir} && \ +// RUN: export EXPECTED_RESOURCE_DIR=%{readfile:%t/resource-dir} // RUN: ln -s %clang++ %t/clang++ && \ // RUN: sed "s|EXPECTED_RESOURCE_DIR|$EXPECTED_RESOURCE_DIR|g; s|DIR|%/t|g" %t/P1689.json.in > %t/P1689.json && \ // RUN: clang-scan-deps -compilation-database %t/P1689.json -format=p1689 | FileCheck %t/a.cpp -DPREFIX=%/t && \