diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py --- a/llvm/utils/lit/lit/TestRunner.py +++ b/llvm/utils/lit/lit/TestRunner.py @@ -608,6 +608,7 @@ assert isinstance(cmd, ShUtil.Pipeline) procs = [] + negate_procs = [] default_stdin = subprocess.PIPE stderrTempFiles = [] opened_files = [] @@ -653,6 +654,12 @@ if not args: raise InternalShellError(j, "Error: 'not' requires a" " subcommand") + elif args[0] == '!': + not_args.append(args.pop(0)) + not_count += 1 + if not args: + raise InternalShellError(j, "Error: '!' requires a" + " subcommand") else: break @@ -699,7 +706,15 @@ # the assumptions that (1) environment variables are not intended to be # relevant to 'not' commands and (2) the 'env' command should always # blindly pass along the status it receives from any command it calls. - args = not_args + args + + # For plain negations, either 'not' without '--crash', or the shell + # operator '!', leave them out from the command to execute and + # invert the result code afterwards. + if not_crash: + args = not_args + args + not_count = 0 + else: + not_args = [] stdin, stdout, stderr = processRedirects(j, default_stdin, cmd_shenv, opened_files) @@ -763,6 +778,7 @@ stderr = stderr, env = cmd_shenv.env, close_fds = kUseCloseFDs)) + negate_procs.append((not_count % 2) != 0) # Let the helper know about this process timeoutHelper.addProcess(procs[-1]) except OSError as e: @@ -815,6 +831,8 @@ # Detect Ctrl-C in subprocess. if res == -signal.SIGINT: raise KeyboardInterrupt + if negate_procs[i]: + res = not res # Ensure the resulting output is always of string type. try: diff --git a/llvm/utils/lit/tests/Inputs/shtest-not/not-calls-external.txt b/llvm/utils/lit/tests/Inputs/shtest-not/not-calls-external.txt --- a/llvm/utils/lit/tests/Inputs/shtest-not/not-calls-external.txt +++ b/llvm/utils/lit/tests/Inputs/shtest-not/not-calls-external.txt @@ -9,6 +9,12 @@ # RUN: not not not %{python} fail.py # RUN: not not not not %{python} pass.py +# Simple uses of '!' + +# RUN: ! %{python} fail.py +# RUN: ! ! %{python} pass.py +# RUN: ! ! ! %{python} fail.py +# RUN: ! ! ! ! %{python} pass.py # Simple uses of 'not --crash'