diff --git a/llvm/docs/TestingGuide.rst b/llvm/docs/TestingGuide.rst
index c35e58bc53b67..08617933519fd 100644
--- a/llvm/docs/TestingGuide.rst
+++ b/llvm/docs/TestingGuide.rst
@@ -864,8 +864,9 @@ Additional substitutions can be defined as follows:
- Lit configuration files (e.g., ``lit.cfg`` or ``lit.local.cfg``) can define
substitutions for all tests in a test directory. They do so by extending the
substitution list, ``config.substitutions``. Each item in the list is a tuple
- consisting of a pattern and its replacement, which lit applies using python's
- ``re.sub`` function.
+ consisting of a pattern and its replacement, which lit applies as plain text
+ (even if it contains sequences that python's ``re.sub`` considers to be
+ escape sequences).
- To define substitutions within a single test file, lit supports the
``DEFINE:`` and ``REDEFINE:`` directives, described in detail below. So that
they have no effect on other test files, these directives modify a copy of the
diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py
index da7fa86fd3917..7f312ad0768f0 100644
--- a/llvm/utils/lit/lit/TestRunner.py
+++ b/llvm/utils/lit/lit/TestRunner.py
@@ -1587,7 +1587,6 @@ def adjust_substitutions(self, substitutions):
assert (
not self.needs_continuation()
), "expected directive continuations to be parsed before applying"
- value_repl = self.value.replace("\\", "\\\\")
existing = [i for i, subst in enumerate(substitutions) if self.name in subst[0]]
existing_res = "".join(
"\nExisting pattern: " + substitutions[i][0] for i in existing
@@ -1600,7 +1599,7 @@ def adjust_substitutions(self, substitutions):
f"{self.get_location()}"
f"{existing_res}"
)
- substitutions.insert(0, (self.name, value_repl))
+ substitutions.insert(0, (self.name, self.value))
return
if len(existing) > 1:
raise ValueError(
@@ -1622,7 +1621,7 @@ def adjust_substitutions(self, substitutions):
f"Expected pattern: {self.name}"
f"{existing_res}"
)
- substitutions[existing[0]] = (self.name, value_repl)
+ substitutions[existing[0]] = (self.name, self.value)
def applySubstitutions(script, substitutions, conditions={}, recursion_limit=None):
@@ -1738,8 +1737,7 @@ def processLine(ln):
# Apply substitutions
ln = substituteIfElse(escapePercents(ln))
for a, b in substitutions:
- if kIsWindows:
- b = b.replace("\\", "\\\\")
+ b = b.replace("\\", "\\\\")
# re.compile() has a built-in LRU cache with 512 entries. In some
# test suites lit ends up thrashing that cache, which made e.g.
# check-llvm run 50% slower. Use an explicit, unbounded cache
diff --git a/llvm/utils/lit/tests/Inputs/shtest-define/lit.cfg b/llvm/utils/lit/tests/Inputs/shtest-define/lit.cfg
index a29755eb2b600..ffe7cce8f0336 100644
--- a/llvm/utils/lit/tests/Inputs/shtest-define/lit.cfg
+++ b/llvm/utils/lit/tests/Inputs/shtest-define/lit.cfg
@@ -23,6 +23,10 @@ config.substitutions.insert(
0, ("%{global:echo}", "echo GLOBAL: %{global:greeting} %{global:what}")
)
+# This substitution includes an re.sub replacement string escape sequence,
+# which lit should treat as plain text.
+config.substitutions.insert(0, ("%{global:subst-with-escapes}", r"value-with-\g"))
+
# The following substitution definitions are confusing and should be avoided.
# We define them here so we can test that 'DEFINE:' and 'REDEFINE:' directives
# guard against the confusion they cause.
diff --git a/llvm/utils/lit/tests/Inputs/shtest-define/value-escaped.txt b/llvm/utils/lit/tests/Inputs/shtest-define/value-escaped.txt
index 68cf35825e2a6..92fe4c27664fa 100644
--- a/llvm/utils/lit/tests/Inputs/shtest-define/value-escaped.txt
+++ b/llvm/utils/lit/tests/Inputs/shtest-define/value-escaped.txt
@@ -1,16 +1,16 @@
-# FIXME: The doubled backslashes occur under windows. That's almost surely a
-# lit issue beyond DEFINE/REDEFINE.
-
# Escape sequences that can appear in python re.sub replacement strings have no
# special meaning in the value.
# DEFINE: %{escape} = \g<0>\n
# RUN: echo '%{escape}'
-# CHECK:# | {{\\?}}\g<0>{{\\?}}\n
+# CHECK:# | \g<0>\n
# REDEFINE: %{escape} = \n \
# REDEFINE: \g
# RUN: echo '%{escape}'
-# CHECK:# | {{\\?}}\n {{\\?}}\g
+# CHECK:# | \n \g
+
+# RUN: echo '%{global:subst-with-escapes}'
+# CHECK:# | value-with-\g
# CHECK: Passed: 1 {{\([0-9]*.[0-9]*%\)}}