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 @@ -1081,9 +1081,7 @@ tmpDir = tmpDir.replace('\\', '/') tmpBase = tmpBase.replace('\\', '/') - # We use #_MARKER_# to hide %% while we do the other substitutions. substitutions = [] - substitutions.extend([('%%', '#_MARKER_#')]) substitutions.extend(test.config.substitutions) tmpName = tmpBase + '.tmp' baseName = os.path.basename(tmpBase) @@ -1093,8 +1091,7 @@ ('%{pathsep}', os.pathsep), ('%t', tmpName), ('%basename_t', baseName), - ('%T', tmpDir), - ('#_MARKER_#', '%')]) + ('%T', tmpDir)]) # "%/[STpst]" should be normalized. substitutions.extend([ @@ -1159,6 +1156,14 @@ `recursion_limit` times, it is an error. If the `recursion_limit` is `None` (the default), no recursive substitution is performed at all. """ + + # We use #_MARKER_# to hide %% while we do the other substitutions. + def escape(ln): + return _caching_re_compile('%%').sub('#_MARKER_#', ln) + + def unescape(ln): + return _caching_re_compile('#_MARKER_#').sub('%', ln) + def processLine(ln): # Apply substitutions for a,b in substitutions: @@ -1171,7 +1176,7 @@ # short-lived, since the set of substitutions is fairly small, and # since thrashing has such bad consequences, not bounding the cache # seems reasonable. - ln = _caching_re_compile(a).sub(b, ln) + ln = _caching_re_compile(a).sub(b, escape(ln)) # Strip the trailing newline and any extra whitespace. return ln.strip() @@ -1193,10 +1198,9 @@ return processed - # Note Python 3 map() gives an iterator rather than a list so explicitly - # convert to list before returning. process = processLine if recursion_limit is None else processLineToFixedPoint - return list(map(process, script)) + + return [unescape(process(ln)) for ln in script] class ParserKind(object): diff --git a/llvm/utils/lit/tests/Inputs/shtest-recursive-substitution/escaping/lit.cfg b/llvm/utils/lit/tests/Inputs/shtest-recursive-substitution/escaping/lit.cfg new file mode 100644 --- /dev/null +++ b/llvm/utils/lit/tests/Inputs/shtest-recursive-substitution/escaping/lit.cfg @@ -0,0 +1,10 @@ +import lit.formats +config.name = 'escaping' +config.suffixes = ['.py'] +config.test_format = lit.formats.ShTest() +config.test_source_root = None +config.test_exec_root = None + +config.substitutions = [("%rec1", "%%s"), ("%rec2", "%rec1")] + +config.recursiveExpansionLimit = 5 diff --git a/llvm/utils/lit/tests/Inputs/shtest-recursive-substitution/escaping/test.py b/llvm/utils/lit/tests/Inputs/shtest-recursive-substitution/escaping/test.py new file mode 100644 --- /dev/null +++ b/llvm/utils/lit/tests/Inputs/shtest-recursive-substitution/escaping/test.py @@ -0,0 +1 @@ +# RUN: echo %rec2 %%s %%%%s diff --git a/llvm/utils/lit/tests/shtest-recursive-substitution.py b/llvm/utils/lit/tests/shtest-recursive-substitution.py --- a/llvm/utils/lit/tests/shtest-recursive-substitution.py +++ b/llvm/utils/lit/tests/shtest-recursive-substitution.py @@ -21,3 +21,7 @@ # RUN: %{lit} -j 1 %{inputs}/shtest-recursive-substitution/set-to-none --show-all | FileCheck --check-prefix=CHECK-TEST6 %s # CHECK-TEST6: PASS: set-to-none :: test.py + +# RUN: %{lit} -j 1 %{inputs}/shtest-recursive-substitution/escaping --show-all | FileCheck --check-prefix=CHECK-TEST7 %s +# CHECK-TEST7: PASS: escaping :: test.py +# CHECK-TEST7: $ "echo" "%s" "%s" "%%s"