1#===----------------------------------------------------------------------===##
2#
3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4# See https://llvm.org/LICENSE.txt for license information.
5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6#
7#===----------------------------------------------------------------------===##
8
9from libcxx.test.dsl import *
10import re
11import shutil
12import sys
13
14_isClang      = lambda cfg: '__clang__' in compilerMacros(cfg) and '__apple_build_version__' not in compilerMacros(cfg)
15_isAppleClang = lambda cfg: '__apple_build_version__' in compilerMacros(cfg)
16_isGCC        = lambda cfg: '__GNUC__' in compilerMacros(cfg) and '__clang__' not in compilerMacros(cfg)
17
18DEFAULT_FEATURES = [
19  Feature(name='fcoroutines-ts',
20          when=lambda cfg: hasCompileFlag(cfg, '-fcoroutines-ts') and
21                           featureTestMacros(cfg, flags='-fcoroutines-ts').get('__cpp_coroutines', 0) >= 201703,
22          actions=[AddCompileFlag('-fcoroutines-ts')]),
23
24  Feature(name='thread-safety',
25          when=lambda cfg: hasCompileFlag(cfg, '-Werror=thread-safety'),
26          actions=[AddCompileFlag('-Werror=thread-safety')]),
27
28  Feature(name='diagnose-if-support',
29          when=lambda cfg: hasCompileFlag(cfg, '-Wuser-defined-warnings'),
30          actions=[AddCompileFlag('-Wuser-defined-warnings')]),
31
32  Feature(name='has-fblocks',                   when=lambda cfg: hasCompileFlag(cfg, '-fblocks')),
33  Feature(name='-fsized-deallocation',          when=lambda cfg: hasCompileFlag(cfg, '-fsized-deallocation')),
34  Feature(name='-faligned-allocation',          when=lambda cfg: hasCompileFlag(cfg, '-faligned-allocation')),
35  Feature(name='fdelayed-template-parsing',     when=lambda cfg: hasCompileFlag(cfg, '-fdelayed-template-parsing')),
36  Feature(name='libcpp-no-if-constexpr',        when=lambda cfg: '__cpp_if_constexpr' not in featureTestMacros(cfg)),
37  Feature(name='libcpp-no-structured-bindings', when=lambda cfg: '__cpp_structured_bindings' not in featureTestMacros(cfg)),
38  Feature(name='libcpp-no-deduction-guides',    when=lambda cfg: featureTestMacros(cfg).get('__cpp_deduction_guides', 0) < 201611),
39  Feature(name='libcpp-no-concepts',            when=lambda cfg: featureTestMacros(cfg).get('__cpp_concepts', 0) < 201811),
40  Feature(name='has-fobjc-arc',                 when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc') and
41                                                                 sys.platform.lower().strip() == 'darwin'), # TODO: this doesn't handle cross-compiling to Apple platforms.
42  Feature(name='objective-c++',                 when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc')),
43
44  # Note: We use a custom modules cache path to make sure that we don't reuse
45  #       the default one, which can be shared across builds. This is important
46  #       because we define macros in headers files, and a change in these macros
47  #       doesn't seem to invalidate modules cache entries, which means we could
48  #       build against now-invalid cached headers from a previous build.
49  Feature(name='modules-support',
50          when=lambda cfg: hasCompileFlag(cfg, '-fmodules'),
51          actions=lambda cfg: [AddCompileFlag('-fmodules-cache-path=%t/ModuleCache')]),
52
53  Feature(name='non-lockfree-atomics',
54          when=lambda cfg: sourceBuilds(cfg, """
55            #include <atomic>
56            struct Large { int storage[100]; };
57            std::atomic<Large> x;
58            int main(int, char**) { (void)x.load(); return 0; }
59          """)),
60  # TODO: Remove this feature once compiler-rt includes __atomic_is_lockfree()
61  # on all supported platforms.
62  Feature(name='is-lockfree-runtime-function',
63          when=lambda cfg: sourceBuilds(cfg, """
64            #include <atomic>
65            struct Large { int storage[100]; };
66            std::atomic<Large> x;
67            int main(int, char**) { return x.is_lock_free(); }
68          """)),
69
70  Feature(name='apple-clang',                                                                                                      when=_isAppleClang),
71  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}'.format(**compilerMacros(cfg)),                                          when=_isAppleClang),
72  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)),                        when=_isAppleClang),
73  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isAppleClang),
74
75  Feature(name='clang',                                                                                                            when=_isClang),
76  Feature(name=lambda cfg: 'clang-{__clang_major__}'.format(**compilerMacros(cfg)),                                                when=_isClang),
77  Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)),                              when=_isClang),
78  Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)),       when=_isClang),
79
80  Feature(name='gcc',                                                                                                              when=_isGCC),
81  Feature(name=lambda cfg: 'gcc-{__GNUC__}'.format(**compilerMacros(cfg)),                                                         when=_isGCC),
82  Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}'.format(**compilerMacros(cfg)),                                        when=_isGCC),
83  Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}'.format(**compilerMacros(cfg)),                  when=_isGCC),
84]
85
86# Deduce and add the test features that that are implied by the #defines in
87# the <__config_site> header.
88#
89# For each macro of the form `_LIBCPP_XXX_YYY_ZZZ` defined below that
90# is defined after including <__config_site>, add a Lit feature called
91# `libcpp-xxx-yyy-zzz`. When a macro is defined to a specific value
92# (e.g. `_LIBCPP_ABI_VERSION=2`), the feature is `libcpp-xxx-yyy-zzz=<value>`.
93macros = {
94  '_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE': 'libcpp-has-no-global-filesystem-namespace',
95  '_LIBCPP_HAS_NO_MONOTONIC_CLOCK': 'libcpp-has-no-monotonic-clock',
96  '_LIBCPP_HAS_NO_STDIN': 'libcpp-has-no-stdin',
97  '_LIBCPP_HAS_NO_STDOUT': 'libcpp-has-no-stdout',
98  '_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS': 'libcpp-has-no-thread-unsafe-c-functions',
99  '_LIBCPP_HAS_NO_THREADS': 'libcpp-has-no-threads',
100  '_LIBCPP_HAS_THREAD_API_EXTERNAL': 'libcpp-has-thread-api-external',
101  '_LIBCPP_HAS_THREAD_API_PTHREAD': 'libcpp-has-thread-api-pthread',
102  '_LIBCPP_NO_VCRUNTIME': 'libcpp-no-vcruntime',
103  '_LIBCPP_ABI_VERSION': 'libcpp-abi-version',
104  '_LIBCPP_ABI_UNSTABLE': 'libcpp-abi-unstable',
105  '_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY': 'libcpp-has-no-filesystem-library',
106  '_LIBCPP_HAS_NO_RANDOM_DEVICE': 'libcpp-has-no-random-device',
107  '_LIBCPP_HAS_NO_LOCALIZATION': 'libcpp-has-no-localization',
108}
109for macro, feature in macros.items():
110  DEFAULT_FEATURES += [
111    Feature(name=lambda cfg, m=macro, f=feature: f + (
112              '={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''
113            ),
114            when=lambda cfg, m=macro: m in compilerMacros(cfg),
115
116            # FIXME: This is a hack that should be fixed using module maps.
117            # If modules are enabled then we have to lift all of the definitions
118            # in <__config_site> onto the command line.
119            actions=lambda cfg, m=macro: [
120              AddCompileFlag('-Wno-macro-redefined -D{}'.format(m) + (
121                '={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''
122              ))
123            ]
124    )
125  ]
126
127
128# Mapping from canonical locale names (used in the tests) to possible locale
129# names on various systems. Each locale is considered supported if any of the
130# alternative names is supported.
131locales = {
132  'en_US.UTF-8':     ['en_US.UTF-8', 'en_US.utf8', 'English_United States.1252'],
133  'fr_FR.UTF-8':     ['fr_FR.UTF-8', 'fr_FR.utf8', 'French_France.1252'],
134  'ru_RU.UTF-8':     ['ru_RU.UTF-8', 'ru_RU.utf8', 'Russian_Russia.1251'],
135  'zh_CN.UTF-8':     ['zh_CN.UTF-8', 'zh_CN.utf8', 'Chinese_China.936'],
136  'fr_CA.ISO8859-1': ['fr_CA.ISO8859-1', 'French_Canada.1252'],
137  'cs_CZ.ISO8859-2': ['cs_CZ.ISO8859-2', 'Czech_Czech Republic.1250']
138}
139for locale, alts in locales.items():
140  # Note: Using alts directly in the lambda body here will bind it to the value at the
141  # end of the loop. Assigning it to a default argument works around this issue.
142  DEFAULT_FEATURES.append(Feature(name='locale.{}'.format(locale),
143                                  when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts)))
144
145
146# Add features representing the platform name: darwin, linux, windows, etc...
147DEFAULT_FEATURES += [
148  Feature(name='darwin', when=lambda cfg: '__APPLE__' in compilerMacros(cfg)),
149  Feature(name='windows', when=lambda cfg: '_WIN32' in compilerMacros(cfg)),
150  Feature(name='linux', when=lambda cfg: '__linux__' in compilerMacros(cfg)),
151  Feature(name='netbsd', when=lambda cfg: '__NetBSD__' in compilerMacros(cfg)),
152  Feature(name='freebsd', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg))
153]
154
155
156# Detect whether GDB is on the system, and if so add a substitution to access it.
157DEFAULT_FEATURES += [
158  Feature(name='host-has-gdb',
159    when=lambda cfg: shutil.which('gdb') is not None,
160    actions=[AddSubstitution('%{gdb}', lambda cfg: shutil.which('gdb'))]
161  )
162]
163
164
165# When vendor-specific availability annotations are enabled, add Lit features
166# with various forms of the target triple to make it easier to write XFAIL or
167# UNSUPPORTED markup for tests that are known to fail on a particular triple.
168#
169# More specifically, when the `use_system_cxx_lib` parameter is enabled, then
170# assuming the `target_triple` is set to `x86_64-apple-macosx10.12`, the
171# following features will be made available:
172#   - with_system_cxx_lib=macosx
173#   - with_system_cxx_lib=macosx10.12
174#   - with_system_cxx_lib=x86_64-apple-macosx10.12
175#
176# These features can be used to XFAIL a test that fails when deployed on (or is
177# compiled for) an older system. For example, if the test exhibits a bug in the
178# libc on a particular system version, or if the test uses a symbol that is not
179# available on an older version of the dylib, it can be marked as XFAIL with
180# one of the above features.
181#
182# It is sometimes useful to check that a test fails specifically when compiled
183# for a given deployment target. For example, this is the case when testing
184# availability markup, where we want to make sure that using the annotated
185# facility on a deployment target that doesn't support it will fail at compile
186# time, not at runtime. This can be achieved by creating a `.compile.pass.cpp`
187# and XFAILing it for the right deployment target. If the test doesn't fail at
188# compile-time like it's supposed to, the test will XPASS. Another option is to
189# create a `.verify.cpp` test that checks for the right errors, and mark that
190# test as requiring `with_system_cxx_lib=<something>`.
191#
192# TODO: This is very unclean -- we assume that the 'use_system_cxx_lib' parameter
193#       is set before this feature gets detected, and we also set a dummy name
194#       for the main feature. We also take for granted that `target_triple`
195#       exists in the config object. This should be refactored so that the
196#       'use_system_cxx_lib' Parameter can set these features itself.
197def _addSystemCxxLibDeclinations(cfg):
198  (arch, vendor, platform) = cfg.target_triple.split('-', 2)
199  (sysname, version) = re.match(r'([^0-9]+)([0-9\.]*)', platform).groups()
200  return [
201    AddFeature('with_system_cxx_lib={}-{}-{}{}'.format(arch, vendor, sysname, version)),
202    AddFeature('with_system_cxx_lib={}{}'.format(sysname, version)),
203    AddFeature('with_system_cxx_lib={}'.format(sysname)),
204  ]
205DEFAULT_FEATURES += [
206  Feature(name='__dummy_use_system_cxx_lib',
207          when=lambda cfg: 'use_system_cxx_lib' in cfg.available_features,
208          actions=_addSystemCxxLibDeclinations)
209]
210