Skip to content

Commit 4dd5c2b

Browse files
committed
[lit] Don't expand escapes until all substitutions have been applied
Otherwise, if a Lit script contains escaped substitutions (like %%p in this test https://github.com/llvm/llvm-project/blob/master/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-partial-report-with-module-map.cpp#L10), they are unescaped during recursive application of substitutions, and the results are unexpected. We solve it using the fact that double percent signs are first replaced with #_MARKER_#, and only after all the other substitutions have been applied, #_MARKER_# is replaced with a single percent sign. The only change is that instead of replacing #_MARKER_# at each recursion step, we replace it once after the last recursion step. Differential Revision: https://reviews.llvm.org/D83894
1 parent 7c18266 commit 4dd5c2b

File tree

4 files changed

+27
-8
lines changed

4 files changed

+27
-8
lines changed

llvm/utils/lit/lit/TestRunner.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,9 +1081,7 @@ def getDefaultSubstitutions(test, tmpDir, tmpBase, normalize_slashes=False):
10811081
tmpDir = tmpDir.replace('\\', '/')
10821082
tmpBase = tmpBase.replace('\\', '/')
10831083

1084-
# We use #_MARKER_# to hide %% while we do the other substitutions.
10851084
substitutions = []
1086-
substitutions.extend([('%%', '#_MARKER_#')])
10871085
substitutions.extend(test.config.substitutions)
10881086
tmpName = tmpBase + '.tmp'
10891087
baseName = os.path.basename(tmpBase)
@@ -1093,8 +1091,7 @@ def getDefaultSubstitutions(test, tmpDir, tmpBase, normalize_slashes=False):
10931091
('%{pathsep}', os.pathsep),
10941092
('%t', tmpName),
10951093
('%basename_t', baseName),
1096-
('%T', tmpDir),
1097-
('#_MARKER_#', '%')])
1094+
('%T', tmpDir)])
10981095

10991096
# "%/[STpst]" should be normalized.
11001097
substitutions.extend([
@@ -1159,6 +1156,14 @@ def applySubstitutions(script, substitutions, recursion_limit=None):
11591156
`recursion_limit` times, it is an error. If the `recursion_limit` is
11601157
`None` (the default), no recursive substitution is performed at all.
11611158
"""
1159+
1160+
# We use #_MARKER_# to hide %% while we do the other substitutions.
1161+
def escape(ln):
1162+
return _caching_re_compile('%%').sub('#_MARKER_#', ln)
1163+
1164+
def unescape(ln):
1165+
return _caching_re_compile('#_MARKER_#').sub('%', ln)
1166+
11621167
def processLine(ln):
11631168
# Apply substitutions
11641169
for a,b in substitutions:
@@ -1171,7 +1176,7 @@ def processLine(ln):
11711176
# short-lived, since the set of substitutions is fairly small, and
11721177
# since thrashing has such bad consequences, not bounding the cache
11731178
# seems reasonable.
1174-
ln = _caching_re_compile(a).sub(str(b), ln)
1179+
ln = _caching_re_compile(a).sub(str(b), escape(ln))
11751180

11761181
# Strip the trailing newline and any extra whitespace.
11771182
return ln.strip()
@@ -1193,10 +1198,9 @@ def processLineToFixedPoint(ln):
11931198

11941199
return processed
11951200

1196-
# Note Python 3 map() gives an iterator rather than a list so explicitly
1197-
# convert to list before returning.
11981201
process = processLine if recursion_limit is None else processLineToFixedPoint
1199-
return list(map(process, script))
1202+
1203+
return [unescape(process(ln)) for ln in script]
12001204

12011205

12021206
class ParserKind(object):
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import lit.formats
2+
config.name = 'escaping'
3+
config.suffixes = ['.py']
4+
config.test_format = lit.formats.ShTest()
5+
config.test_source_root = None
6+
config.test_exec_root = None
7+
8+
config.substitutions = [("%rec1", "%%s"), ("%rec2", "%rec1")]
9+
10+
config.recursiveExpansionLimit = 5
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# RUN: echo %rec2 %%s %%%%s

llvm/utils/lit/tests/shtest-recursive-substitution.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@
2121

2222
# RUN: %{lit} -j 1 %{inputs}/shtest-recursive-substitution/set-to-none --show-all | FileCheck --check-prefix=CHECK-TEST6 %s
2323
# CHECK-TEST6: PASS: set-to-none :: test.py
24+
25+
# RUN: %{lit} -j 1 %{inputs}/shtest-recursive-substitution/escaping --show-all | FileCheck --check-prefix=CHECK-TEST7 %s
26+
# CHECK-TEST7: PASS: escaping :: test.py
27+
# CHECK-TEST7: $ "echo" "%s" "%s" "%%s"

0 commit comments

Comments
 (0)