Index: clang/test/Index/recover-bad-code-rdar_7487294.c =================================================================== --- clang/test/Index/recover-bad-code-rdar_7487294.c +++ clang/test/Index/recover-bad-code-rdar_7487294.c @@ -1,4 +1,4 @@ -// RUN: not %clang-cc1 -fsyntax-only %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s // IMPORTANT: This test case intentionally DOES NOT use --disable-free. It // tests that we are properly reclaiming the ASTs and we do not have a double free. Index: clang/test/lit.cfg.py =================================================================== --- clang/test/lit.cfg.py +++ clang/test/lit.cfg.py @@ -10,7 +10,8 @@ import lit.util from lit.llvm import llvm_config -from lit.llvm import ToolFilter +from lit.llvm.subst import ToolSubst +from lit.llvm.subst import FindTool # Configuration file for the 'lit' test runner. @@ -76,6 +77,8 @@ llvm_config.with_system_environment( ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']) +llvm_config.use_default_substitutions() + # Discover the 'clang' and 'clangcc' to use. @@ -120,44 +123,37 @@ config.available_features.add('examples') builtin_include_dir = llvm_config.get_clang_builtin_include_dir(config.clang) -config.substitutions.append(('%clang_analyze_cc1', - '%clang_cc1 -analyze %analyze')) -config.substitutions.append(('%clang_cc1', - '%s -cc1 -internal-isystem %s -nostdsysteminc' - % (config.clang, builtin_include_dir))) -config.substitutions.append(('%clang_cpp', ' ' + config.clang + - ' --driver-mode=cpp ')) -config.substitutions.append(('%clang_cl', ' ' + config.clang + - ' --driver-mode=cl ')) -config.substitutions.append(('%clangxx', ' ' + config.clang + - ' --driver-mode=g++ ')) - -clang_func_map = lit.util.which( - 'clang-func-mapping', config.environment['PATH']) -if clang_func_map: - config.substitutions.append( - ('%clang_func_map', ' ' + clang_func_map + ' ')) - -config.substitutions.append(('%clang', ' ' + config.clang + ' ')) -config.substitutions.append(('%test_debuginfo', - ' ' + config.llvm_src_root + '/utils/test_debuginfo.pl ')) -config.substitutions.append(('%itanium_abi_triple', - llvm_config.make_itanium_abi_triple(config.target_triple))) -config.substitutions.append(('%ms_abi_triple', - llvm_config.make_msabi_triple(config.target_triple))) -config.substitutions.append(('%resource_dir', builtin_include_dir)) -config.substitutions.append(('%python', config.python_executable)) -# The host triple might not be set, at least if we're compiling clang from -# an already installed llvm. -if config.host_triple and config.host_triple != '@LLVM_HOST_TRIPLE@': - config.substitutions.append(('%target_itanium_abi_host_triple', - '--target=%s' % llvm_config.make_itanium_abi_triple(config.host_triple))) -else: - config.substitutions.append(('%target_itanium_abi_host_triple', '')) +tools = [ + # By specifying %clang_cc1 as part of the substitution, this substitution + # relies on repeated substitution, so must come before %clang_cc1. + ToolSubst('%clang_analyze_cc1', command='%clang_cc1', + extra_args=['-analyze', '%analyze']), + ToolSubst('%clang_cc1', command=config.clang, extra_args=[ + '-cc1', '-internal-isystem', builtin_include_dir, '-nostdsysteminc']), + ToolSubst('%clang_cpp', command=config.clang, + extra_args=['--driver-mode=cpp']), + ToolSubst('%clang_cl', command=config.clang, + extra_args=['--driver-mode=cl']), + ToolSubst('%clangxx', command=config.clang, + extra_args=['--driver-mode=g++']), + ToolSubst('%clang_func_map', command=FindTool( + 'clang-func-mapping'), unresolved='ignore'), + ToolSubst('%clang', command=config.clang), + ToolSubst('%test_debuginfo', command=os.path.join( + config.llvm_src_root, 'utils', 'test_debuginfo.pl')), + 'c-index-test', 'clang-check', 'clang-diff', 'clang-format', 'opt'] -config.substitutions.append( - ('%src_include_dir', config.clang_src_dir + '/include')) +if config.clang_examples: + tools.append('clang-interpreter') + +# For each occurrence of a clang tool name, replace it with the full path to +# the build directory holding that tool. We explicitly specify the directories +# to search to ensure that we get the tools just built and not some random +# tools that might happen to be in the user's PATH. +tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir] + +llvm_config.add_tool_substitutions(tools, tool_dirs) # FIXME: Find nicer way to prohibit this. config.substitutions.append( @@ -183,27 +179,22 @@ (' %clang-cl ', """*** invalid substitution, use '%clang_cl'. ***""")) -# For each occurrence of a clang tool name, replace it with the full path to -# the build directory holding that tool. We explicitly specify the directories -# to search to ensure that we get the tools just built and not some random -# tools that might happen to be in the user's PATH. -tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir] - -tool_patterns = [ - 'FileCheck', 'c-index-test', - ToolFilter('clang-check', pre='-.', post='-.'), - ToolFilter('clang-diff', pre='-.', post='-.'), - ToolFilter('clang-format', pre='-.', post='-.'), - # FIXME: Some clang test uses opt? - ToolFilter('opt', pre='-.', post=r'/\-.'), - # Handle these specially as they are strings searched for during testing. - ToolFilter(r'\| \bcount\b', verbatim=True), - ToolFilter(r'\| \bnot\b', verbatim=True)] +config.substitutions.append(('%itanium_abi_triple', + llvm_config.make_itanium_abi_triple(config.target_triple))) +config.substitutions.append(('%ms_abi_triple', + llvm_config.make_msabi_triple(config.target_triple))) +config.substitutions.append(('%resource_dir', builtin_include_dir)) -if config.clang_examples: - tool_patterns.append(ToolFilter('clang-interpreter', '-.', '-.')) +# The host triple might not be set, at least if we're compiling clang from +# an already installed llvm. +if config.host_triple and config.host_triple != '@LLVM_HOST_TRIPLE@': + config.substitutions.append(('%target_itanium_abi_host_triple', + '--target=%s' % llvm_config.make_itanium_abi_triple(config.host_triple))) +else: + config.substitutions.append(('%target_itanium_abi_host_triple', '')) -llvm_config.add_tool_substitutions(tool_patterns, tool_dirs) +config.substitutions.append( + ('%src_include_dir', config.clang_src_dir + '/include')) # Set available features we allow tests to conditionalize on. # Index: lld/test/lit.cfg.py =================================================================== --- lld/test/lit.cfg.py +++ lld/test/lit.cfg.py @@ -10,7 +10,7 @@ import lit.util from lit.llvm import llvm_config -from lit.llvm import ToolFilter +from lit.llvm.subst import ToolSubst # Configuration file for the 'lit' test runner. @@ -43,24 +43,22 @@ llvm_config.with_environment('LD_LIBRARY_PATH', [config.lld_libs_dir, config.llvm_libs_dir], append_path=True) +llvm_config.use_default_substitutions() + # For each occurrence of a clang tool name, replace it with the full path to # the build directory holding that tool. We explicitly specify the directories # to search to ensure that we get the tools just built and not some random # tools that might happen to be in the user's PATH. tool_dirs = [config.lld_tools_dir, config.llvm_tools_dir] -config.substitutions.append((r"\bld.lld\b", 'ld.lld --full-shutdown')) - tool_patterns = [ - 'FileCheck', 'not', 'ld.lld', 'lld-link', 'llvm-as', 'llvm-mc', 'llvm-nm', + ToolSubst('ld.lld', extra_args=['--full-shutdown']), + 'lld-link', 'llvm-as', 'llvm-mc', 'llvm-nm', 'llvm-objdump', 'llvm-pdbutil', 'llvm-readobj', 'obj2yaml', 'yaml2obj', - ToolFilter('lld', pre='-./', post='-.')] + 'lld'] llvm_config.add_tool_substitutions(tool_patterns, tool_dirs) -# Add site-specific substitutions. -config.substitutions.append(('%python', config.python_executable)) - # When running under valgrind, we mangle '-vg' onto the end of the triple so we # can check it with XFAIL and XTARGET. if lit_config.useValgrind: Index: llvm/test/lit.cfg.py =================================================================== --- llvm/test/lit.cfg.py +++ llvm/test/lit.cfg.py @@ -11,7 +11,8 @@ import lit.util import lit.formats from lit.llvm import llvm_config -from lit.llvm import ToolFilter +from lit.llvm.subst import FindTool +from lit.llvm.subst import ToolSubst # name: The name of this test suite. config.name = 'LLVM' @@ -82,31 +83,30 @@ return found_dylibs[0] -lli = 'lli' +llvm_config.use_default_substitutions() + +# Add site-specific substitutions. +config.substitutions.append(('%llvmshlibdir', config.llvm_shlib_dir)) +config.substitutions.append(('%shlibext', config.llvm_shlib_ext)) +config.substitutions.append(('%exeext', config.llvm_exe_ext)) +config.substitutions.append(('%host_cc', config.host_cc)) + + +lli_args = [] # The target triple used by default by lli is the process target triple (some # triple appropriate for generating code for the current process) but because # we don't support COFF in MCJIT well enough for the tests, force ELF format on # Windows. FIXME: the process target triple should be used here, but this is # difficult to obtain on Windows. if re.search(r'cygwin|mingw32|windows-gnu|windows-msvc|win32', config.host_triple): - lli += ' -mtriple=' + config.host_triple + '-elf' -config.substitutions.append(('%lli', lli)) + lli_args = ['-mtriple=' + config.host_triple + '-elf'] + +llc_args = [] # Similarly, have a macro to use llc with DWARF even when the host is win32. -llc_dwarf = 'llc' if re.search(r'win32', config.target_triple): - llc_dwarf += ' -mtriple=' + \ - config.target_triple.replace('-win32', '-mingw32') -config.substitutions.append(('%llc_dwarf', llc_dwarf)) - -# Add site-specific substitutions. -config.substitutions.append(('%gold', config.gold_executable)) -config.substitutions.append(('%go', config.go_executable)) -config.substitutions.append(('%llvmshlibdir', config.llvm_shlib_dir)) -config.substitutions.append(('%shlibext', config.llvm_shlib_ext)) -config.substitutions.append(('%exeext', config.llvm_exe_ext)) -config.substitutions.append(('%python', config.python_executable)) -config.substitutions.append(('%host_cc', config.host_cc)) + llc_args = [' -mtriple=' + + config.target_triple.replace('-win32', '-mingw32')] # Provide the path to asan runtime lib if available. On darwin, this lib needs # to be loaded via DYLD_INSERT_LIBRARIES before libLTO.dylib in case the files @@ -115,35 +115,27 @@ asan_rtlib = get_asan_rtlib() if asan_rtlib: ld64_cmd = 'DYLD_INSERT_LIBRARIES={} {}'.format(asan_rtlib, ld64_cmd) -config.substitutions.append(('%ld64', ld64_cmd)) -# OCaml substitutions. -# Support tests for both native and bytecode builds. -config.substitutions.append(('%ocamlc', - '%s ocamlc -cclib -L%s %s' % - (config.ocamlfind_executable, config.llvm_lib_dir, config.ocaml_flags))) +ocamlc_command = '%s ocamlc -cclib -L%s %s' % ( + config.ocamlfind_executable, config.llvm_lib_dir, config.ocaml_flags) +ocamlopt_command = 'true' if config.have_ocamlopt: - config.substitutions.append(('%ocamlopt', - '%s ocamlopt -cclib -L%s -cclib -Wl,-rpath,%s %s' % - (config.ocamlfind_executable, config.llvm_lib_dir, config.llvm_lib_dir, config.ocaml_flags))) -else: - config.substitutions.append(('%ocamlopt', 'true')) - -# For each occurrence of an llvm tool name as its own word, replace it -# with the full path to the build directory holding that tool. This -# ensures that we are testing the tools just built and not some random -# tools that might happen to be in the user's PATH. Thus this list -# includes every tool placed in $(LLVM_OBJ_ROOT)/$(BuildMode)/bin -# (llvm_tools_dir in lit parlance). - -# Avoid matching RUN line fragments that are actually part of -# path names or options or whatever. -# The regex is a pre-assertion to avoid matching a preceding -# dot, hyphen, carat, or slash (.foo, -foo, etc.). Some patterns -# also have a post-assertion to not match a trailing hyphen (foo-). -JUNKCHARS = r".-^/<" - -required_tools = [ + ocamlopt_command = '%s ocamlopt -cclib -L%s -cclib -Wl,-rpath,%s %s' % ( + config.ocamlfind_executable, config.llvm_lib_dir, config.llvm_lib_dir, config.ocaml_flags) + + +tools = [ + ToolSubst('%lli', FindTool('lli'), extra_args=lli_args), + ToolSubst('%llc_dwarf', FindTool('llc'), extra_args=llc_args), + ToolSubst('%go', config.go_executable, unresolved='ignore'), + ToolSubst('%gold', config.gold_executable, unresolved='ignore'), + ToolSubst('%ld64', ld64_cmd, unresolved='ignore'), + ToolSubst('%ocamlc', ocamlc_command, unresolved='ignore'), + ToolSubst('%ocamlopt', ocamlopt_command, unresolved='ignore'), +] + +# FIXME: Why do we have both `lli` and `%lli` that do slightly different things? +tools.extend([ 'lli', 'llvm-ar', 'llvm-as', 'llvm-bcanalyzer', 'llvm-config', 'llvm-cov', 'llvm-cxxdump', 'llvm-cvtres', 'llvm-diff', 'llvm-dis', 'llvm-dsymutil', 'llvm-dwarfdump', 'llvm-extract', 'llvm-isel-fuzzer', 'llvm-lib', @@ -152,28 +144,21 @@ 'llvm-pdbutil', 'llvm-profdata', 'llvm-ranlib', 'llvm-readobj', 'llvm-rtdyld', 'llvm-size', 'llvm-split', 'llvm-strings', 'llvm-tblgen', 'llvm-c-test', 'llvm-cxxfilt', 'llvm-xray', 'yaml2obj', 'obj2yaml', - 'FileCheck', 'yaml-bench', 'verify-uselistorder', - ToolFilter('bugpoint', post='-'), - ToolFilter('llc', pre=JUNKCHARS), - ToolFilter('llvm-symbolizer', pre=JUNKCHARS), - ToolFilter('opt', JUNKCHARS), - ToolFilter('sancov', pre=JUNKCHARS), - ToolFilter('sanstats', pre=JUNKCHARS), - # Handle these specially as they are strings searched for during testing. - ToolFilter(r'\| \bcount\b', verbatim=True), - ToolFilter(r'\| \bnot\b', verbatim=True)] - -llvm_config.add_tool_substitutions(required_tools, config.llvm_tools_dir) - -# For tools that are optional depending on the config, we won't warn -# if they're missing. - -optional_tools = [ - 'llvm-go', 'llvm-mt', 'Kaleidoscope-Ch3', 'Kaleidoscope-Ch4', - 'Kaleidoscope-Ch5', 'Kaleidoscope-Ch6', 'Kaleidoscope-Ch7', - 'Kaleidoscope-Ch8'] -llvm_config.add_tool_substitutions(optional_tools, config.llvm_tools_dir, - warn_missing=False) + 'yaml-bench', 'verify-uselistorder', + 'bugpoint', 'llc', 'llvm-symbolizer', 'opt', 'sancov', 'sanstats']) + +# The following tools are optional +tools.extend([ + ToolSubst('llvm-go', unresolved='ignore'), + ToolSubst('llvm-mt', unresolved='ignore'), + ToolSubst('Kaleidoscope-Ch3', unresolved='ignore'), + ToolSubst('Kaleidoscope-Ch4', unresolved='ignore'), + ToolSubst('Kaleidoscope-Ch5', unresolved='ignore'), + ToolSubst('Kaleidoscope-Ch6', unresolved='ignore'), + ToolSubst('Kaleidoscope-Ch7', unresolved='ignore'), + ToolSubst('Kaleidoscope-Ch8', unresolved='ignore')]) + +llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir) # Targets Index: llvm/utils/lit/lit/llvm/__init__.py =================================================================== --- llvm/utils/lit/lit/llvm/__init__.py +++ llvm/utils/lit/lit/llvm/__init__.py @@ -1,51 +1,9 @@ from lit.llvm import config -import lit.util -import re llvm_config = None -class ToolFilter(object): - """ - String-like class used to build regex substitution patterns for - llvm tools. Handles things like adding word-boundary patterns, - and filtering characters from the beginning an end of a tool name - """ - - def __init__(self, name, pre=None, post=None, verbatim=False): - """ - Construct a ToolFilter. - - name: the literal name of the substitution to look for. - - pre: If specified, the substitution will not find matches where - the character immediately preceding the word-boundary that begins - `name` is any of the characters in the string `pre`. - - post: If specified, the substitution will not find matches where - the character immediately after the word-boundary that ends `name` - is any of the characters specified in the string `post`. - - verbatim: If True, `name` is an exact regex that is passed to the - underlying substitution - """ - if verbatim: - self.regex = name - return - - def not_in(chars, where=''): - if not chars: - return '' - pattern_str = '|'.join(re.escape(x) for x in chars) - return r'(?{}!({}))'.format(where, pattern_str) - - self.regex = not_in(pre, '<') + r'\b' + name + r'\b' + not_in(post) - - def __str__(self): - return self.regex - def initialize(lit_config, test_config): global llvm_config llvm_config = config.LLVMConfig(lit_config, test_config) - Index: llvm/utils/lit/lit/llvm/config.py =================================================================== --- llvm/utils/lit/lit/llvm/config.py +++ llvm/utils/lit/lit/llvm/config.py @@ -5,6 +5,8 @@ import sys import lit.util +from lit.llvm.subst import FindTool +from lit.llvm.subst import ToolSubst def binary_feature(on, feature, off_prefix): @@ -225,41 +227,47 @@ # -win32 is not supported for non-x86 targets; use a default. return 'i686-pc-win32' - def add_tool_substitutions(self, tools, search_dirs, warn_missing=True): + def add_tool_substitutions(self, tools, search_dirs=None): + if not search_dirs: + search_dirs = [self.config.llvm_tools_dir] + if lit.util.is_string(search_dirs): search_dirs = [search_dirs] + tools = [x if isinstance(x, ToolSubst) else ToolSubst(x) + for x in tools] + search_dirs = os.pathsep.join(search_dirs) + substitutions = [] + for tool in tools: - # Extract the tool name from the pattern. This relies on the tool - # name being surrounded by \b word match operators. If the - # pattern starts with "| ", include it in the string to be - # substituted. - if lit.util.is_string(tool): - tool = lit.util.make_word_regex(tool) - else: - tool = str(tool) + match = tool.resolve(self, search_dirs) - tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_\.]+)\\b\W*$", - tool) - if not tool_match: + # Either no match occurred, or there was an unresolved match that + # is ignored. + if not match: continue - tool_pipe = tool_match.group(2) - tool_name = tool_match.group(4) - tool_path = lit.util.which(tool_name, search_dirs) - if not tool_path: - if warn_missing: - # Warn, but still provide a substitution. - self.lit_config.note( - 'Did not find ' + tool_name + ' in %s' % search_dirs) - tool_path = self.config.llvm_tools_dir + '/' + tool_name - - if tool_name == 'llc' and os.environ.get('LLVM_ENABLE_MACHINE_VERIFIER') == '1': - tool_path += ' -verify-machineinstrs' - if tool_name == 'llvm-go': - exe = getattr(self.config, 'go_executable', None) - if exe: - tool_path += ' go=' + exe - - self.config.substitutions.append((tool, tool_pipe + tool_path)) + subst_key, tool_pipe, command = match + + # An unresolved match occurred that can't be ignored. Fail without + # adding any of the previously-discovered substitutions. + if not command: + return False + + substitutions.append((subst_key, tool_pipe + command)) + + self.config.substitutions.extend(substitutions) + return True + + def use_default_substitutions(self): + tool_patterns = [ + ToolSubst('FileCheck', unresolved='fatal'), + # Handle these specially as they are strings searched for during testing. + ToolSubst(r'\| \bcount\b', command=FindTool( + 'count'), verbatim=True, unresolved='fatal'), + ToolSubst(r'\| \bnot\b', command=FindTool('not'), verbatim=True, unresolved='fatal')] + + self.config.substitutions.append(('%python', sys.executable)) + self.add_tool_substitutions( + tool_patterns, [self.config.llvm_tools_dir]) Index: llvm/utils/lit/lit/llvm/subst.py =================================================================== --- /dev/null +++ llvm/utils/lit/lit/llvm/subst.py @@ -0,0 +1,140 @@ +import os +import re + +import lit.util + +expr = re.compile(r"^(\\)?((\| )?)\W+b(\S+)\\b\W*$") +wordifier = re.compile(r"(\W*)(\b[^\b]+\b)") + + +class FindTool(object): + def __init__(self, name): + self.name = name + + def resolve(self, config, dirs): + command = lit.util.which(self.name, dirs) + if not command: + return None + + if self.name == 'llc' and os.environ.get('LLVM_ENABLE_MACHINE_VERIFIER') == '1': + command += ' -verify-machineinstrs' + elif self.name == 'llvm-go': + exe = getattr(config.config, 'go_executable', None) + if exe: + command += ' go=' + exe + return command + + +class ToolSubst(object): + """String-like class used to build regex substitution patterns for llvm + tools. + + Handles things like adding word-boundary patterns, and filtering + characters from the beginning an end of a tool name + + """ + + def __init__(self, key, command=None, pre=r'.-^/\<', post='-.', verbatim=False, + unresolved='warn', extra_args=None): + """Construct a ToolSubst. + + key: The text which is to be substituted. + + command: The command to substitute when the key is matched. By default, + this will treat `key` as a tool name and search for it. If it is + a string, it is intereprted as an exact path. If it is an instance of + FindTool, the specified tool name is searched for on disk. + + pre: If specified, the substitution will not find matches where + the character immediately preceding the word-boundary that begins + `key` is any of the characters in the string `pre`. + + post: If specified, the substitution will not find matches where + the character immediately after the word-boundary that ends `key` + is any of the characters specified in the string `post`. + + verbatim: If True, `key` is an exact regex that is passed to the + underlying substitution + + unresolved: Action to take if the tool substitution cannot be + resolved. Valid values: + 'warn' - log a warning but add the substitution anyway. + 'fatal' - Exit the test suite and log a fatal error. + 'break' - Don't add any of the substitutions from the current + group, and return a value indicating a failure. + 'ignore' - Don't add the substitution, and don't log an error + + extra_args: If specified, represents a list of arguments that will be + appended to the tool's substitution. + + explicit_path: If specified, the exact path will be used as a substitution. + Otherwise, the tool will be searched for as if by calling which(tool) + + """ + self.unresolved = unresolved + self.extra_args = extra_args + self.key = key + self.command = command if command is not None else FindTool(key) + if verbatim: + self.regex = key + return + + def not_in(chars, where=''): + if not chars: + return '' + pattern_str = '|'.join(re.escape(x) for x in chars) + return r'(?{}!({}))'.format(where, pattern_str) + + def wordify(word): + match = wordifier.match(word) + introducer = match.group(1) + word = match.group(2) + return introducer + r'\b' + word + r'\b' + + self.regex = not_in(pre, '<') + wordify(key) + not_in(post) + + def resolve(self, config, search_dirs): + # Extract the tool name from the pattern. This relies on the tool + # name being surrounded by \b word match operators. If the + # pattern starts with "| ", include it in the string to be + # substituted. + + tool_match = expr.match(self.regex) + if not tool_match: + return None + + tool_pipe = tool_match.group(2) + tool_name = tool_match.group(4) + + if isinstance(self.command, FindTool): + command_str = self.command.resolve(config, search_dirs) + else: + command_str = str(self.command) + + if command_str: + if self.extra_args: + command_str = ' '.join([command_str] + self.extra_args) + else: + if self.unresolved == 'warn': + # Warn, but still provide a substitution. + config.lit_config.note( + 'Did not find ' + tool_name + ' in %s' % search_dirs) + command_str = os.path.join( + config.config.llvm_tools_dir, tool_name) + elif self.unresolved == 'fatal': + # The function won't even return in this case, this leads to + # sys.exit + config.lit_config.fatal( + 'Did not find ' + tool_name + ' in %s' % search_dirs) + elif self.unresolved == 'break': + # By returning a valid result with an empty command, the + # caller treats this as a failure. + pass + elif self.unresolved == 'ignore': + # By returning None, the caller just assumes there was no + # match in the first place. + return None + else: + raise 'Unexpected value for ToolSubst.unresolved' + + return (self.regex, tool_pipe, command_str) Index: llvm/utils/lit/lit/util.py =================================================================== --- llvm/utils/lit/lit/util.py +++ llvm/utils/lit/lit/util.py @@ -195,7 +195,7 @@ # Check for absolute match first. if os.path.isfile(command): - return command + return os.path.normpath(command) # Would be nice if Python had a lib function for this. if not paths: @@ -213,7 +213,7 @@ for ext in pathext: p = os.path.join(path, command + ext) if os.path.exists(p) and not os.path.isdir(p): - return p + return os.path.normpath(p) return None