[llvm] [Lit] Introduce a new IO interface for in-process built-ins (PR #194664)
Benjamin Stott via llvm-commits
llvm-commits at lists.llvm.org
Fri May 8 09:48:54 PDT 2026
https://github.com/BStott6 updated https://github.com/llvm/llvm-project/pull/194664
>From 77aee6aa287f8ff1f6c253cd03aba1eae424973b Mon Sep 17 00:00:00 2001
From: BStott <Benjamin.Stott at sony.com>
Date: Mon, 27 Apr 2026 18:00:53 +0100
Subject: [PATCH 1/2] Introduce a new IO interface for in-process builtins
---
llvm/utils/lit/lit/InprocBuiltins.py | 391 +++++++++++++++++++++------
llvm/utils/lit/lit/TestRunner.py | 54 ++--
llvm/utils/lit/tests/shtest-glob.py | 3 +-
llvm/utils/lit/tests/shtest-shell.py | 37 +--
4 files changed, 356 insertions(+), 129 deletions(-)
diff --git a/llvm/utils/lit/lit/InprocBuiltins.py b/llvm/utils/lit/lit/InprocBuiltins.py
index b20aeb6993726..9479f774b72c6 100644
--- a/llvm/utils/lit/lit/InprocBuiltins.py
+++ b/llvm/utils/lit/lit/InprocBuiltins.py
@@ -1,87 +1,297 @@
+from __future__ import acknnotations
+
+import abc
import getopt
+import io
import os
import pathlib
-import platform
import shutil
import stat
import subprocess
-from io import StringIO
+from dataclasses import dataclass
+from typing import Callable, Optional
import lit.util
+from lit.ShCommands import Command
from lit.ShellEnvironment import (
InternalShellError,
- ShellCommandResult,
- expand_glob_expressions,
+ ShellEnvironment,
kIsWindows,
- processRedirects,
updateEnv,
)
-def executeBuiltinCd(cmd, shenv):
+class InprocBuiltinIOObject(abc.ABC):
+ """
+ Base class for IO streams used for in-process built-ins. This class has two
+ specializations: InprocBuiltinIOFile, wrapping a file open in text mode, and
+ InprocBuiltinIOMemory, wrapping a BytesIO object. These streams provide
+ a text IO interface, but support reading and writing binary data too.
+
+ The main reason that this exists is to solve the conflict that binary IO is
+ required for the daemonized testing project, as many tests involve tools
+ reading and writing binary files and piping binary data between themselves,
+ but for regular testing on z/OS, files must be opened in text mode so that
+ the character encoding is correct. So we need an IO object that can be both
+ a file open in text mode and a in-memory stream that can store binary data.
+ """
+
+ @abc.abstractmethod
+ def read(self) -> str:
+ raise NotImplemented
+
+ @abc.abstractmethod
+ def read_binary(self) -> bytes:
+ raise NotImplemented
+
+ @abc.abstractmethod
+ def write(self, data: str) -> int:
+ raise NotImplemented
+
+ @abc.abstractmethod
+ def write_binary(self, data: bytes) -> int:
+ raise NotImplemented
+
+ @abc.abstractmethod
+ def seek(self, pos: int):
+ raise NotImplemented
+
+ @abc.abstractmethod
+ def flush(self):
+ raise NotImplemented
+
+ @abc.abstractmethod
+ def get_filename(self) -> str | None:
+ raise NotImplemented
+
+ @abc.abstractmethod
+ def get_encoding(self) -> str | None:
+ raise NotImplemented
+
+
+ at dataclass
+class InprocBuiltinIOFile(InprocBuiltinIOObject):
+ """
+ Specialization of InprocBuiltinIOObject wrapping a file which is open in
+ text mode. Files must be opened in text mode so that character encoding
+ tags are correctly handled on z/OS. Binary IO is still supported via the
+ OS APIs (needed for daemonized testing).
+ """
+
+ file: io.TextIOBase
+
+ def read(self) -> str:
+ return self.file.read()
+
+ def read_binary(self) -> bytes:
+ self.file.flush()
+ data = bytearray()
+ chunk_size = 1024
+
+ while True:
+ chunk = os.read(self.file.fileno(), chunk_size)
+ if not chunk:
+ break
+ data.extend(chunk)
+
+ return bytes(data)
+
+ def write(self, data: str) -> int:
+ return self.file.write(data)
+
+ def write_binary(self, data: bytes) -> int:
+ self.file.flush()
+ return os.write(self.file.fileno(), data)
+
+ def seek(self, pos: int):
+ self.file.seek(pos)
+
+ def flush(self):
+ self.file.flush()
+
+ def get_filename(self) -> str | None:
+ if hasattr(self.file, "name") and isinstance(self.file.name, str):
+ return self.file.name
+ return None
+
+ def get_encoding(self) -> str | None:
+ return str(self.file.encoding)
+
+
+ at dataclass
+class InprocBuiltinIOMemory(InprocBuiltinIOObject):
+ """
+ Specialization of InprocBuiltinIOObject wrapping an in-memory binary stream.
+ """
+
+ obj: io.BytesIO
+ encoding: str = "utf-8"
+
+ def read(self) -> str:
+ return self.obj.read().decode(self.encoding, errors="replace")
+
+ def read_binary(self) -> bytes:
+ return self.obj.read()
+
+ def write(self, data: str) -> int:
+ return self.obj.write(data.encode(self.encoding, errors="replace"))
+
+ def write_binary(self, data: bytes) -> int:
+ return self.obj.write(data)
+
+ def seek(self, pos: int):
+ self.obj.seek(pos)
+
+ def flush(self):
+ pass
+
+ def get_filename(self) -> str | None:
+ return None
+
+ def get_encoding(self) -> str | None:
+ return self.encoding
+
+
+class InprocBuiltinIO:
+ """
+ Holds IO streams for an inproc builtin invocation.
+
+ NB: If stderr is redirected to be the same stream as stdout, then
+ `stder == stdout` is True.
+ """
+
+ stdin: InprocBuiltinIOObject
+ stdout: InprocBuiltinIOObject
+ stderr: InprocBuiltinIOObject
+
+ def __init__(self, stdin, stdout, stderr):
+ """
+ Configure the IO streams for an in-process builtin command in
+ the same way that IO streams are configured when calling
+ `subprocess.Popen`.
+
+ Each of stdin, stdout and stderr may be:
+ - A file object open in binary mode.
+ - `subprocess.PIPE`
+ - `subprocess.STDOUT` (for stderr)
+ - None
+ """
+
+ # If stderr is redirected to stdout, we make sure to use the same
+ # stream for both so that the order of output is preserved.
+ stderr_redirected_to_stdout = (
+ stdout == subprocess.PIPE and stderr == subprocess.STDOUT
+ )
+
+ # Replace sentinel values with in-memory streams.
+ def resolve_io_obj(stream) -> InprocBuiltinIOObject:
+ if stream == subprocess.PIPE or stream is None:
+ return InprocBuiltinIOMemory(io.BytesIO())
+ elif isinstance(stream, InprocBuiltinIOObject):
+ return stream
+ else:
+ return InprocBuiltinIOFile(stream)
+
+ self.stdin = resolve_io_obj(stdin)
+ self.stdout = resolve_io_obj(stdout)
+ if stderr_redirected_to_stdout:
+ # Make sure stderr and stdout are directed to the same stream.
+ self.stderr = self.stdout
+ else:
+ self.stderr = resolve_io_obj(stderr)
+
+
+InprocBuiltinExecuteFn = Callable[
+ [Command, "list[str]", ShellEnvironment, InprocBuiltinIO],
+ int,
+]
+"""
+Function called by an in-process builtin command.
+Parameters:
+ - `cmd`: The command itself.
+ - `args`: glob-expanded list of arguments (including argv[0] as the program name).
+ - `shenv`: The shell environment.
+ - `io`: Holds the input and output streams for the invocation. These are file-like objects (files, StringIO)
+
+The return value is the exit code.
+"""
+
+
+ at dataclass
+class InprocBuiltin:
+ """
+ Represents a command that is run as an in-process builtins.
+ """
+
+ execute: InprocBuiltinExecuteFn
+
+
+def executeBuiltinCd(
+ cmd: Command, args: list[str], shenv: ShellEnvironment, io: InprocBuiltinIO
+) -> int:
"""executeBuiltinCd - Change the current directory."""
- if len(cmd.args) != 2:
+ if len(args) != 2:
raise InternalShellError(cmd, "'cd' supports only one argument")
# Update the cwd in the parent environment.
- shenv.change_dir(cmd.args[1])
+ shenv.change_dir(args[1])
# The cd builtin always succeeds. If the directory does not exist, the
# following Popen calls will fail instead.
- return ShellCommandResult(cmd, "", "", 0, False)
+ return 0
-def executeBuiltinPushd(cmd, shenv):
+def executeBuiltinPushd(
+ cmd: Command, args: list[str], shenv: ShellEnvironment, io: InprocBuiltinIO
+) -> int:
"""executeBuiltinPushd - Change the current dir and save the old."""
- if len(cmd.args) != 2:
+ if len(args) != 2:
raise InternalShellError(cmd, "'pushd' supports only one argument")
shenv.dirStack.append(shenv.cwd)
- shenv.change_dir(cmd.args[1])
- return ShellCommandResult(cmd, "", "", 0, False)
+ shenv.change_dir(args[1])
+ return 0
-def executeBuiltinPopd(cmd, shenv):
+def executeBuiltinPopd(
+ cmd: Command, args: list[str], shenv: ShellEnvironment, io: InprocBuiltinIO
+) -> int:
"""executeBuiltinPopd - Restore a previously saved working directory."""
- if len(cmd.args) != 1:
+ if len(args) != 1:
raise InternalShellError(cmd, "'popd' does not support arguments")
if not shenv.dirStack:
raise InternalShellError(cmd, "popd: directory stack empty")
shenv.cwd = shenv.dirStack.pop()
- return ShellCommandResult(cmd, "", "", 0, False)
+ return 0
-def executeBuiltinExport(cmd, shenv):
+def executeBuiltinExport(
+ cmd: Command, args: list[str], shenv: ShellEnvironment, io: InprocBuiltinIO
+) -> int:
"""executeBuiltinExport - Set an environment variable."""
- if len(cmd.args) != 2:
+ if len(args) != 2:
raise InternalShellError(cmd, "'export' supports only one argument")
- updateEnv(shenv, cmd.args)
- return ShellCommandResult(cmd, "", "", 0, False)
+ updateEnv(shenv, args)
+ return 0
-def executeBuiltinEcho(cmd, shenv):
+def executeBuiltinEcho(
+ cmd: Command, args: list[str], shenv: ShellEnvironment, io: InprocBuiltinIO
+) -> int:
"""Interpret a redirected echo or @echo command"""
- opened_files = []
- stdin, stdout, stderr = processRedirects(cmd, subprocess.PIPE, shenv, opened_files)
- if stdin != subprocess.PIPE or stderr != subprocess.PIPE:
- raise InternalShellError(
- cmd, f"stdin and stderr redirects not supported for {cmd.args[0]}"
- )
-
- # Some tests have un-redirected echo commands to help debug test failures.
- # Buffer our output and return it to the caller.
- is_redirected = True
- if stdout == subprocess.PIPE:
- is_redirected = False
- stdout = StringIO()
- elif kIsWindows:
+ if (
+ kIsWindows
+ and isinstance(io.stdout, InprocBuiltinIOFile)
+ and io.stdout.get_filename()
+ ):
# Reopen stdout with `newline=""` to avoid CRLF translation.
# The versions of echo we are replacing on Windows all emit plain LF,
# and the LLVM tests now depend on this.
- stdout = open(stdout.name, stdout.mode, encoding="utf-8", newline="")
- opened_files.append((None, None, stdout, None))
+ io.stdout.file = os.fdopen(
+ io.stdout.file.fileno(), io.stdout.file.mode, encoding="utf-8", newline=""
+ )
# Implement echo flags. We only support -e and -n, and not yet in
# combination. We have to ignore unknown flags, because `echo "-D FOO"`
# prints the dash.
- args = cmd.args[1:]
+ args = args[1:]
interpret_escapes = False
write_newline = True
while len(args) >= 1 and args[0] in ("-e", "-n"):
@@ -100,24 +310,21 @@ def maybeUnescape(arg):
if args:
for arg in args[:-1]:
- stdout.write(maybeUnescape(arg))
- stdout.write(" ")
- stdout.write(maybeUnescape(args[-1]))
+ io.stdout.write(maybeUnescape(arg))
+ io.stdout.write(" ")
+ io.stdout.write(maybeUnescape(args[-1]))
if write_newline:
- stdout.write("\n")
-
- for name, mode, f, path in opened_files:
- f.close()
+ io.stdout.write("\n")
- output = "" if is_redirected else stdout.getvalue()
- return ShellCommandResult(cmd, output, "", 0, False)
+ return 0
-def executeBuiltinMkdir(cmd, cmd_shenv):
+def executeBuiltinMkdir(
+ cmd: Command, args: list[str], cmd_shenv: ShellEnvironment, io: InprocBuiltinIO
+):
"""executeBuiltinMkdir - Create new directories."""
- args = expand_glob_expressions(cmd.args, cmd_shenv.cwd)[1:]
try:
- opts, args = getopt.gnu_getopt(args, "p")
+ opts, args = getopt.gnu_getopt(args[1:], "p")
except getopt.GetoptError as err:
raise InternalShellError(cmd, "Unsupported: 'mkdir': %s" % str(err))
@@ -131,7 +338,6 @@ def executeBuiltinMkdir(cmd, cmd_shenv):
if len(args) == 0:
raise InternalShellError(cmd, "Error: 'mkdir' is missing an operand")
- stderr = StringIO()
exitCode = 0
for dir in args:
dir = pathlib.Path(dir)
@@ -144,16 +350,17 @@ def executeBuiltinMkdir(cmd, cmd_shenv):
try:
dir.mkdir(exist_ok=True)
except OSError as err:
- stderr.write("Error: 'mkdir' command failed, %s\n" % str(err))
+ io.stderr.write(("Error: 'mkdir' command failed, %s\n" % str(err)))
exitCode = 1
- return ShellCommandResult(cmd, "", stderr.getvalue(), exitCode, False)
+ return exitCode
-def executeBuiltinRm(cmd, cmd_shenv):
+def executeBuiltinRm(
+ cmd: Command, args: list[str], cmd_shenv: ShellEnvironment, io: InprocBuiltinIO
+):
"""executeBuiltinRm - Removes (deletes) files or directories."""
- args = expand_glob_expressions(cmd.args, cmd_shenv.cwd)[1:]
try:
- opts, args = getopt.gnu_getopt(args, "frR", ["--recursive"])
+ opts, args = getopt.gnu_getopt(args[1:], "frR", ["--recursive"])
except getopt.GetoptError as err:
raise InternalShellError(cmd, "Unsupported: 'rm': %s" % str(err))
@@ -176,7 +383,6 @@ def on_rm_error(func, path, exc_info):
os.chmod(path, stat.S_IMODE(os.stat(path).st_mode) | stat.S_IWRITE)
os.remove(path)
- stderr = StringIO()
exitCode = 0
for path in args:
cwd = cmd_shenv.cwd
@@ -189,9 +395,9 @@ def on_rm_error(func, path, exc_info):
os.remove(path)
elif os.path.isdir(path):
if not recursive:
- stderr.write("Error: %s is a directory\n" % path)
+ io.stderr.write(("Error: %s is a directory\n" % path))
exitCode = 1
- if platform.system() == "Windows":
+ if kIsWindows:
# NOTE: use ctypes to access `SHFileOperationsW` on Windows to
# use the NT style path to get access to long file paths which
# cannot be removed otherwise.
@@ -255,26 +461,28 @@ class SHFILEOPSTRUCTW(Structure):
os.chmod(path, stat.S_IMODE(os.stat(path).st_mode) | stat.S_IWRITE)
os.remove(path)
except OSError as err:
- stderr.write("Error: 'rm' command failed, %s" % str(err))
+ io.stderr.write(("Error: 'rm' command failed, %s" % str(err)))
exitCode = 1
- return ShellCommandResult(cmd, "", stderr.getvalue(), exitCode, False)
+ return exitCode
-def executeBuiltinUmask(cmd, shenv):
+def executeBuiltinUmask(
+ cmd: Command, args: list[str], shenv: ShellEnvironment, io: InprocBuiltinIO
+):
"""executeBuiltinUmask - Change the current umask."""
if os.name != "posix":
raise InternalShellError(cmd, "'umask' not supported on this system")
- if len(cmd.args) != 2:
+ if len(args) != 2:
raise InternalShellError(cmd, "'umask' supports only one argument")
try:
# Update the umask in the parent environment.
- shenv.umask = int(cmd.args[1], 8)
+ shenv.umask = int(args[1], 8)
except ValueError as err:
raise InternalShellError(cmd, "Error: 'umask': %s" % str(err))
- return ShellCommandResult(cmd, "", "", 0, False)
+ return 0
-def executeBuiltinUlimit(cmd, shenv):
+def executeBuiltinUlimit(cmd: Command, args: list[str], shenv, io: InprocBuiltinIO):
"""executeBuiltinUlimit - Change the current limits."""
try:
# Try importing the resource module (available on POSIX systems) and
@@ -282,34 +490,59 @@ def executeBuiltinUlimit(cmd, shenv):
import resource
except ImportError:
raise InternalShellError(cmd, "'ulimit' not supported on this system")
- if len(cmd.args) != 3:
+ if len(args) != 3:
raise InternalShellError(cmd, "'ulimit' requires two arguments")
try:
- if cmd.args[2] == "unlimited":
+ if args[2] == "unlimited":
new_limit = resource.RLIM_INFINITY
else:
- new_limit = int(cmd.args[2])
+ new_limit = int(args[2])
except ValueError as err:
raise InternalShellError(cmd, "Error: 'ulimit': %s" % str(err))
- if cmd.args[1] == "-v":
+ if args[1] == "-v":
if new_limit != resource.RLIM_INFINITY:
new_limit = new_limit * 1024
shenv.ulimit["RLIMIT_AS"] = new_limit
- elif cmd.args[1] == "-n":
+ elif args[1] == "-n":
shenv.ulimit["RLIMIT_NOFILE"] = new_limit
- elif cmd.args[1] == "-s":
+ elif args[1] == "-s":
if new_limit != resource.RLIM_INFINITY:
new_limit = new_limit * 1024
shenv.ulimit["RLIMIT_STACK"] = new_limit
- elif cmd.args[1] == "-f":
+ elif args[1] == "-f":
shenv.ulimit["RLIMIT_FSIZE"] = new_limit
else:
- raise InternalShellError(
- cmd, "'ulimit' does not support option: %s" % cmd.args[1]
- )
- return ShellCommandResult(cmd, "", "", 0, False)
+ raise InternalShellError(cmd, "'ulimit' does not support option: %s" % args[1])
+ return 0
-def executeBuiltinColon(cmd, cmd_shenv):
+def executeBuiltinColon(
+ cmd: Command, args: list[str], cmd_shenv: ShellEnvironment, io: InprocBuiltinIO
+):
"""executeBuiltinColon - Discard arguments and exit with status 0."""
- return ShellCommandResult(cmd, "", "", 0, False)
+ return 0
+
+
+def get_default_inproc_builtins() -> dict[str, InprocBuiltin]:
+ """
+ get_default_inproc_builtins - Returns the map of command names to Lit's
+ in-process built-in implementations.
+ The entries are a pair of the callable for the builtin and a bool
+ that determines whether this inproc builtin may fall back to a
+ command of the same name in cases where in-proc builtins cannot be
+ used (e.g. as the argument to not --crash).
+ """
+
+ return {
+ "@echo": InprocBuiltin(executeBuiltinEcho, None),
+ "cd": InprocBuiltin(executeBuiltinCd, None),
+ "export": InprocBuiltin(executeBuiltinExport, None),
+ "echo": InprocBuiltin(executeBuiltinEcho, None),
+ "mkdir": InprocBuiltin(executeBuiltinMkdir, None),
+ "popd": InprocBuiltin(executeBuiltinPopd, None),
+ "pushd": InprocBuiltin(executeBuiltinPushd, None),
+ "rm": InprocBuiltin(executeBuiltinRm, None),
+ "ulimit": InprocBuiltin(executeBuiltinUlimit, None),
+ "umask": InprocBuiltin(executeBuiltinUmask, None),
+ ":": InprocBuiltin(executeBuiltinColon, None),
+ }
diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py
index 82852f1852705..89eebe27f94c0 100644
--- a/llvm/utils/lit/lit/TestRunner.py
+++ b/llvm/utils/lit/lit/TestRunner.py
@@ -11,11 +11,11 @@
import threading
import traceback
-import lit.InprocBuiltins as InprocBuiltins
import lit.ShUtil as ShUtil
import lit.Test as Test
import lit.util
from lit.BooleanExpression import BooleanExpression
+from lit.InprocBuiltins import InprocBuiltinIO, get_default_inproc_builtins
from lit.ShCommands import Command
from lit.ShellEnvironment import (
InternalShellError,
@@ -254,19 +254,7 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper):
builtin_commands_dir = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "builtin_commands"
)
- inproc_builtins = {
- "cd": InprocBuiltins.executeBuiltinCd,
- "export": InprocBuiltins.executeBuiltinExport,
- "echo": InprocBuiltins.executeBuiltinEcho,
- "@echo": InprocBuiltins.executeBuiltinEcho,
- "mkdir": InprocBuiltins.executeBuiltinMkdir,
- "popd": InprocBuiltins.executeBuiltinPopd,
- "pushd": InprocBuiltins.executeBuiltinPushd,
- "rm": InprocBuiltins.executeBuiltinRm,
- "ulimit": InprocBuiltins.executeBuiltinUlimit,
- "umask": InprocBuiltins.executeBuiltinUmask,
- ":": InprocBuiltins.executeBuiltinColon,
- }
+ inproc_builtins = get_default_inproc_builtins()
# To avoid deadlock, we use a single stderr stream for piped
# output. This is null until we have seen some output using
# stderr.
@@ -354,9 +342,43 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper):
j,
"Unsupported: '{}' cannot be part" " of a pipeline".format(args[0]),
)
- result = inproc_builtin(Command(args, j.redirects), cmd_shenv)
+
+ stdin, stdout, stderr = processRedirects(
+ j, subprocess.PIPE, shenv, opened_files
+ )
+
+ builtin_io = InprocBuiltinIO(stdin, stdout, stderr)
+
+ args = expand_glob_expressions(args, cmd_shenv.cwd)
+
+ exit_code = inproc_builtin.execute(
+ Command(args, j.redirects), args, cmd_shenv, builtin_io
+ )
+
+ builtin_io.stdout.flush()
+ builtin_io.stderr.flush()
+
if not_count % 2:
- result.exitCode = int(not result.exitCode)
+ exit_code = int(not exit_code)
+
+ # Gather output from the streams.
+ out = ""
+ if stdout == subprocess.PIPE:
+ builtin_io.stdout.seek(0)
+ out = builtin_io.stdout.read()
+
+ err = ""
+ if stderr == subprocess.PIPE:
+ builtin_io.stderr.seek(0)
+ err = builtin_io.stderr.read()
+
+ result = ShellCommandResult(
+ j,
+ out,
+ err,
+ exit_code,
+ False,
+ )
result.command.args = j.args
results.append(result)
return result.exitCode
diff --git a/llvm/utils/lit/tests/shtest-glob.py b/llvm/utils/lit/tests/shtest-glob.py
index ba609e036c166..190745f8133d4 100644
--- a/llvm/utils/lit/tests/shtest-glob.py
+++ b/llvm/utils/lit/tests/shtest-glob.py
@@ -4,8 +4,7 @@
# RUN: | FileCheck -dump-input=fail -match-full-lines --implicit-check-not=Error: %s
# END.
-# CHECK: UNRESOLVED: shtest-glob :: glob-echo.txt ({{[^)]*}})
-# CHECK: TypeError: string argument expected, got 'GlobItem'
+# CHECK: PASS: shtest-glob :: glob-echo.txt ({{[^)]*}})
# CHECK: FAIL: shtest-glob :: glob-mkdir.txt ({{[^)]*}})
# CHECK: # | Error: 'mkdir' command failed, {{.*}}example_file1.input'
diff --git a/llvm/utils/lit/tests/shtest-shell.py b/llvm/utils/lit/tests/shtest-shell.py
index 498f6bb0adc11..fa5d63b5e9e29 100644
--- a/llvm/utils/lit/tests/shtest-shell.py
+++ b/llvm/utils/lit/tests/shtest-shell.py
@@ -497,37 +497,10 @@
# CHECK-NEXT: # error: command failed with exit status: 1
# CHECK: ***
-# CHECK: FAIL: shtest-shell :: echo-at-redirect-stderr.txt
-# CHECK: *** TEST 'shtest-shell :: echo-at-redirect-stderr.txt' FAILED ***
-# CHECK: @echo 2> {{.*}}
-# CHECK: # executed command: @echo
-# CHECK: # .---command stderr{{-*}}
-# CHECK: # | stdin and stderr redirects not supported for @echo
-# CHECK: error: command failed with exit status:
-
-# CHECK: FAIL: shtest-shell :: echo-at-redirect-stdin.txt
-# CHECK: *** TEST 'shtest-shell :: echo-at-redirect-stdin.txt' FAILED ***
-# CHECK: @echo < {{.*}}
-# CHECK: # executed command: @echo
-# CHECK: # .---command stderr{{-*}}
-# CHECK: # | stdin and stderr redirects not supported for @echo
-# CHECK: error: command failed with exit status:
-
-# CHECK: FAIL: shtest-shell :: echo-redirect-stderr.txt
-# CHECK: *** TEST 'shtest-shell :: echo-redirect-stderr.txt' FAILED ***
-# CHECK: echo 2> {{.*}}
-# CHECK: # executed command: echo
-# CHECK: # .---command stderr{{-*}}
-# CHECK: # | stdin and stderr redirects not supported for echo
-# CHECK: error: command failed with exit status:
-
-# CHECK: FAIL: shtest-shell :: echo-redirect-stdin.txt
-# CHECK: *** TEST 'shtest-shell :: echo-redirect-stdin.txt' FAILED ***
-# CHECK: echo < {{.*}}
-# CHECK: # executed command: echo
-# CHECK: # .---command stderr{{-*}}
-# CHECK: # | stdin and stderr redirects not supported for echo
-# CHECK: error: command failed with exit status:
+# CHECK: PASS: shtest-shell :: echo-at-redirect-stderr.txt
+# CHECK: PASS: shtest-shell :: echo-at-redirect-stdin.txt
+# CHECK: PASS: shtest-shell :: echo-redirect-stderr.txt
+# CHECK: PASS: shtest-shell :: echo-redirect-stdin.txt
# CHECK: FAIL: shtest-shell :: error-0.txt
# CHECK: *** TEST 'shtest-shell :: error-0.txt' FAILED ***
@@ -634,4 +607,4 @@
# CHECK: PASS: shtest-shell :: valid-shell.txt
# CHECK: Unresolved Tests (1)
-# CHECK: Failed Tests (37)
+# CHECK: Failed Tests (33)
>From 08967aa144824a4b126a882ea979480fe54e97fb Mon Sep 17 00:00:00 2001
From: BStott <Benjamin.Stott at sony.com>
Date: Fri, 8 May 2026 17:47:08 +0100
Subject: [PATCH 2/2] Fix some last-minute accidents
---
llvm/utils/lit/lit/InprocBuiltins.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/llvm/utils/lit/lit/InprocBuiltins.py b/llvm/utils/lit/lit/InprocBuiltins.py
index 9479f774b72c6..9b1cd5eda3b21 100644
--- a/llvm/utils/lit/lit/InprocBuiltins.py
+++ b/llvm/utils/lit/lit/InprocBuiltins.py
@@ -1,4 +1,4 @@
-from __future__ import acknnotations
+from __future__ import annotations
import abc
import getopt
@@ -534,15 +534,15 @@ def get_default_inproc_builtins() -> dict[str, InprocBuiltin]:
"""
return {
- "@echo": InprocBuiltin(executeBuiltinEcho, None),
- "cd": InprocBuiltin(executeBuiltinCd, None),
- "export": InprocBuiltin(executeBuiltinExport, None),
- "echo": InprocBuiltin(executeBuiltinEcho, None),
- "mkdir": InprocBuiltin(executeBuiltinMkdir, None),
- "popd": InprocBuiltin(executeBuiltinPopd, None),
- "pushd": InprocBuiltin(executeBuiltinPushd, None),
- "rm": InprocBuiltin(executeBuiltinRm, None),
- "ulimit": InprocBuiltin(executeBuiltinUlimit, None),
- "umask": InprocBuiltin(executeBuiltinUmask, None),
- ":": InprocBuiltin(executeBuiltinColon, None),
+ "@echo": InprocBuiltin(executeBuiltinEcho),
+ "cd": InprocBuiltin(executeBuiltinCd),
+ "export": InprocBuiltin(executeBuiltinExport),
+ "echo": InprocBuiltin(executeBuiltinEcho),
+ "mkdir": InprocBuiltin(executeBuiltinMkdir),
+ "popd": InprocBuiltin(executeBuiltinPopd),
+ "pushd": InprocBuiltin(executeBuiltinPushd),
+ "rm": InprocBuiltin(executeBuiltinRm),
+ "ulimit": InprocBuiltin(executeBuiltinUlimit),
+ "umask": InprocBuiltin(executeBuiltinUmask),
+ ":": InprocBuiltin(executeBuiltinColon),
}
More information about the llvm-commits
mailing list