From 61b9a7258a7693d7f3674a5a1daf7b036ff1d382 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sun, 6 Sep 2015 18:46:46 +0000 Subject: Import libc++ 3.7.0 release (r246257). --- test/libcxx/__init__.py | 0 test/libcxx/compiler.py | 152 +++++ .../unord/unord.set/insert_dup_alloc.pass.cpp | 48 ++ test/libcxx/double_include.sh.cpp | 114 ++++ .../header.algorithm.synop/includes.pass.cpp | 20 + .../experimental/algorithms/version.pass.cpp | 20 + .../dynarray/dynarray.cons/alloc.pass.cpp | 86 +++ .../dynarray/dynarray.cons/default.pass.cpp | 95 +++ .../dynarray/dynarray.data/default.pass.cpp | 67 ++ .../dynarray/dynarray.mutate/default.pass.cpp | 48 ++ .../dynarray/dynarray.overview/at.pass.cpp | 94 +++ .../dynarray/dynarray.overview/begin_end.pass.cpp | 108 ++++ .../dynarray/dynarray.overview/capacity.pass.cpp | 57 ++ .../dynarray/dynarray.overview/front_back.pass.cpp | 68 ++ .../dynarray/dynarray.overview/indexing.pass.cpp | 71 +++ .../dynarray/dynarray.traits/default.pass.cpp | 31 + .../dynarray/dynarray.zero/default.pass.cpp | 50 ++ .../sequences/dynarray/nothing_to_do.pass.cpp | 12 + .../ratio/header.ratio.synop/includes.pass.cpp | 24 + .../experimental/utilities/ratio/version.pass.cpp | 20 + .../header.system_error.synop/includes.pass.cpp | 22 + .../utilities/syserror/version.pass.cpp | 20 + .../time/header.chrono.synop/includes.pass.cpp | 22 + .../experimental/utilities/time/version.pass.cpp | 20 + .../tuple/header.tuple.synop/includes.pass.cpp | 21 + .../experimental/utilities/tuple/version.pass.cpp | 20 + test/libcxx/selftest/not_test.sh.cpp | 17 + test/libcxx/selftest/test.fail.cpp | 11 + test/libcxx/selftest/test.pass.cpp | 13 + test/libcxx/selftest/test.sh.cpp | 16 + test/libcxx/selftest/test_macros.pass.cpp | 58 ++ test/libcxx/test/__init__.py | 0 test/libcxx/test/config.py | 709 +++++++++++++++++++++ test/libcxx/test/executor.py | 191 ++++++ test/libcxx/test/format.py | 163 +++++ test/libcxx/test/target_info.py | 55 ++ test/libcxx/test/tracing.py | 34 + .../type_traits/convert_to_integral.pass.cpp | 94 +++ test/libcxx/util.py | 46 ++ .../memory/util.smartptr/race_condition.pass.cpp | 94 +++ 40 files changed, 2811 insertions(+) create mode 100644 test/libcxx/__init__.py create mode 100644 test/libcxx/compiler.py create mode 100644 test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp create mode 100644 test/libcxx/double_include.sh.cpp create mode 100644 test/libcxx/experimental/algorithms/header.algorithm.synop/includes.pass.cpp create mode 100644 test/libcxx/experimental/algorithms/version.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.cons/alloc.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.cons/default.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.data/default.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.mutate/default.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/at.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/begin_end.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/capacity.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/front_back.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/indexing.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.traits/default.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/dynarray.zero/default.pass.cpp create mode 100644 test/libcxx/experimental/containers/sequences/dynarray/nothing_to_do.pass.cpp create mode 100644 test/libcxx/experimental/utilities/ratio/header.ratio.synop/includes.pass.cpp create mode 100644 test/libcxx/experimental/utilities/ratio/version.pass.cpp create mode 100644 test/libcxx/experimental/utilities/syserror/header.system_error.synop/includes.pass.cpp create mode 100644 test/libcxx/experimental/utilities/syserror/version.pass.cpp create mode 100644 test/libcxx/experimental/utilities/time/header.chrono.synop/includes.pass.cpp create mode 100644 test/libcxx/experimental/utilities/time/version.pass.cpp create mode 100644 test/libcxx/experimental/utilities/tuple/header.tuple.synop/includes.pass.cpp create mode 100644 test/libcxx/experimental/utilities/tuple/version.pass.cpp create mode 100644 test/libcxx/selftest/not_test.sh.cpp create mode 100644 test/libcxx/selftest/test.fail.cpp create mode 100644 test/libcxx/selftest/test.pass.cpp create mode 100644 test/libcxx/selftest/test.sh.cpp create mode 100644 test/libcxx/selftest/test_macros.pass.cpp create mode 100644 test/libcxx/test/__init__.py create mode 100644 test/libcxx/test/config.py create mode 100644 test/libcxx/test/executor.py create mode 100644 test/libcxx/test/format.py create mode 100644 test/libcxx/test/target_info.py create mode 100644 test/libcxx/test/tracing.py create mode 100644 test/libcxx/type_traits/convert_to_integral.pass.cpp create mode 100644 test/libcxx/util.py create mode 100644 test/libcxx/utilities/memory/util.smartptr/race_condition.pass.cpp (limited to 'test/libcxx') diff --git a/test/libcxx/__init__.py b/test/libcxx/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/libcxx/compiler.py b/test/libcxx/compiler.py new file mode 100644 index 000000000000..7afbed461e31 --- /dev/null +++ b/test/libcxx/compiler.py @@ -0,0 +1,152 @@ +import os +import lit.util +import libcxx.util + + +class CXXCompiler(object): + def __init__(self, path, flags=None, compile_flags=None, link_flags=None, + use_ccache=False): + self.path = path + self.flags = list(flags or []) + self.compile_flags = list(compile_flags or []) + self.link_flags = list(link_flags or []) + self.use_ccache = use_ccache + self.type = None + self.version = None + self._initTypeAndVersion() + + def _initTypeAndVersion(self): + # Get compiler type and version + macros = self.dumpMacros() + if macros is None: + return + compiler_type = None + major_ver = minor_ver = patchlevel = None + if '__clang__' in macros.keys(): + compiler_type = 'clang' + # Treat apple's llvm fork differently. + if '__apple_build_version__' in macros.keys(): + compiler_type = 'apple-clang' + major_ver = macros['__clang_major__'] + minor_ver = macros['__clang_minor__'] + patchlevel = macros['__clang_patchlevel__'] + elif '__GNUC__' in macros.keys(): + compiler_type = 'gcc' + major_ver = macros['__GNUC__'] + minor_ver = macros['__GNUC_MINOR__'] + patchlevel = macros['__GNUC_PATCHLEVEL__'] + self.type = compiler_type + self.version = (major_ver, minor_ver, patchlevel) + + def _basicCmd(self, source_files, out, is_link=False, input_is_cxx=False): + cmd = [] + if self.use_ccache and not is_link: + cmd += ['ccache'] + cmd += [self.path] + if out is not None: + cmd += ['-o', out] + if input_is_cxx: + cmd += ['-x', 'c++'] + if isinstance(source_files, list): + cmd += source_files + elif isinstance(source_files, str): + cmd += [source_files] + else: + raise TypeError('source_files must be a string or list') + return cmd + + def preprocessCmd(self, source_files, out=None, flags=[]): + cmd = self._basicCmd(source_files, out, input_is_cxx=True) + ['-E'] + cmd += self.flags + self.compile_flags + flags + return cmd + + def compileCmd(self, source_files, out=None, flags=[]): + cmd = self._basicCmd(source_files, out, input_is_cxx=True) + ['-c'] + cmd += self.flags + self.compile_flags + flags + return cmd + + def linkCmd(self, source_files, out=None, flags=[]): + cmd = self._basicCmd(source_files, out, is_link=True) + cmd += self.flags + self.link_flags + flags + return cmd + + def compileLinkCmd(self, source_files, out=None, flags=[]): + cmd = self._basicCmd(source_files, out, is_link=True) + cmd += self.flags + self.compile_flags + self.link_flags + flags + return cmd + + def preprocess(self, source_files, out=None, flags=[], env=None, cwd=None): + cmd = self.preprocessCmd(source_files, out, flags) + out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd) + return cmd, out, err, rc + + def compile(self, source_files, out=None, flags=[], env=None, cwd=None): + cmd = self.compileCmd(source_files, out, flags) + out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd) + return cmd, out, err, rc + + def link(self, source_files, out=None, flags=[], env=None, cwd=None): + cmd = self.linkCmd(source_files, out, flags) + out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd) + return cmd, out, err, rc + + def compileLink(self, source_files, out=None, flags=[], env=None, + cwd=None): + cmd = self.compileLinkCmd(source_files, out, flags) + out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd) + return cmd, out, err, rc + + def compileLinkTwoSteps(self, source_file, out=None, object_file=None, + flags=[], env=None, cwd=None): + if not isinstance(source_file, str): + raise TypeError('This function only accepts a single input file') + if object_file is None: + # Create, use and delete a temporary object file if none is given. + with_fn = lambda: libcxx.util.guardedTempFilename(suffix='.o') + else: + # Otherwise wrap the filename in a context manager function. + with_fn = lambda: libcxx.util.nullContext(object_file) + with with_fn() as object_file: + cc_cmd, cc_stdout, cc_stderr, rc = self.compile( + source_file, object_file, flags=flags, env=env, cwd=cwd) + if rc != 0: + return cc_cmd, cc_stdout, cc_stderr, rc + + link_cmd, link_stdout, link_stderr, rc = self.link( + object_file, out=out, flags=flags, env=env, cwd=cwd) + return (cc_cmd + ['&&'] + link_cmd, cc_stdout + link_stdout, + cc_stderr + link_stderr, rc) + + def dumpMacros(self, source_files=None, flags=[], env=None, cwd=None): + if source_files is None: + source_files = os.devnull + flags = ['-dM'] + flags + cmd, out, err, rc = self.preprocess(source_files, flags=flags, env=env, + cwd=cwd) + if rc != 0: + return None + parsed_macros = {} + lines = [l.strip() for l in out.split('\n') if l.strip()] + for l in lines: + assert l.startswith('#define ') + l = l[len('#define '):] + macro, _, value = l.partition(' ') + parsed_macros[macro] = value + return parsed_macros + + def getTriple(self): + cmd = [self.path] + self.flags + ['-dumpmachine'] + return lit.util.capture(cmd).strip() + + def hasCompileFlag(self, flag): + if isinstance(flag, list): + flags = list(flag) + else: + flags = [flag] + # Add -Werror to ensure that an unrecognized flag causes a non-zero + # exit code. -Werror is supported on all known compiler types. + if self.type is not None: + flags += ['-Werror'] + cmd, out, err, rc = self.compile(os.devnull, out=os.devnull, + flags=flags) + return rc == 0 diff --git a/test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp b/test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp new file mode 100644 index 000000000000..76ceafed2208 --- /dev/null +++ b/test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Check that we don't allocate when trying to insert a duplicate value into a +// unordered_set. See PR12999 http://llvm.org/bugs/show_bug.cgi?id=12999 + +#include +#include +#include "count_new.hpp" +#include "MoveOnly.h" + +int main() +{ + { + std::unordered_set s; + assert(globalMemCounter.checkNewCalledEq(0)); + + for(int i=0; i < 100; ++i) + s.insert(3); + + assert(s.size() == 1); + assert(s.count(3) == 1); + assert(globalMemCounter.checkNewCalledEq(2)); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + globalMemCounter.reset(); +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + { + std::unordered_set s; + assert(globalMemCounter.checkNewCalledEq(0)); + + for(int i=0; i<100; i++) + s.insert(MoveOnly(3)); + + assert(s.size() == 1); + assert(s.count(MoveOnly(3)) == 1); + assert(globalMemCounter.checkNewCalledEq(2)); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + globalMemCounter.reset(); +#endif +} diff --git a/test/libcxx/double_include.sh.cpp b/test/libcxx/double_include.sh.cpp new file mode 100644 index 000000000000..5620e5b35c2b --- /dev/null +++ b/test/libcxx/double_include.sh.cpp @@ -0,0 +1,114 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Test that we can include each header in two TU's and link them together. + +// RUN: %cxx -c %s -o %t.first.o %flags %compile_flags +// RUN: %cxx -c %s -o %t.second.o -DWITH_MAIN %flags %compile_flags +// RUN: %cxx -o %t.exe %t.first.o %t.second.o %flags %link_flags +// RUN: %run + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _LIBCPP_HAS_NO_THREADS +#include +#include +#include +#include +#include +#endif + +#if defined(WITH_MAIN) +int main() {} +#endif diff --git a/test/libcxx/experimental/algorithms/header.algorithm.synop/includes.pass.cpp b/test/libcxx/experimental/algorithms/header.algorithm.synop/includes.pass.cpp new file mode 100644 index 000000000000..accdd699c4f9 --- /dev/null +++ b/test/libcxx/experimental/algorithms/header.algorithm.synop/includes.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#ifndef _LIBCPP_ALGORITHM +# error " must include " +#endif + +int main() +{ +} diff --git a/test/libcxx/experimental/algorithms/version.pass.cpp b/test/libcxx/experimental/algorithms/version.pass.cpp new file mode 100644 index 000000000000..6d9d0c6b2f38 --- /dev/null +++ b/test/libcxx/experimental/algorithms/version.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#ifndef _LIBCPP_VERSION +# error _LIBCPP_VERSION not defined +#endif + +int main() +{ +} diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.cons/alloc.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.cons/alloc.pass.cpp new file mode 100644 index 000000000000..d274bc030881 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.cons/alloc.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.cons + +// template +// dynarray(size_type c, const Alloc& alloc); +// template +// dynarray(size_type c, const T& v, const Alloc& alloc); +// template +// dynarray(const dynarray& d, const Alloc& alloc); +// template +// dynarray(initializer_list, const Alloc& alloc); + +// ~dynarray(); + + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include +#include "test_allocator.h" + +using std::experimental::dynarray; + +template +void check_allocator ( const dynarray &dyn, const Allocator &alloc ) { + for ( int i = 0; i < dyn.size (); ++i ) + assert ( dyn[i].get_allocator() == alloc ); +} + +template +void test ( const std::initializer_list &vals, const Allocator &alloc ) { + typedef dynarray dynA; + + dynA d1 ( vals, alloc ); + assert ( d1.size () == vals.size() ); + assert ( std::equal ( vals.begin (), vals.end (), d1.begin (), d1.end ())); + check_allocator ( d1, alloc ); + } + + +template +void test ( const T &val, const Allocator &alloc1, const Allocator &alloc2 ) { + typedef dynarray dynA; + + dynA d1 ( 4, alloc1 ); + assert ( d1.size () == 4 ); + assert ( std::all_of ( d1.begin (), d1.end (), []( const T &item ){ return item == T(); } )); + check_allocator ( d1, alloc1 ); + + dynA d2 ( 7, val, alloc1 ); + assert ( d2.size () == 7 ); + assert ( std::all_of ( d2.begin (), d2.end (), [&val]( const T &item ){ return item == val; } )); + check_allocator ( d2, alloc1 ); + + dynA d3 ( d2, alloc2 ); + assert ( d3.size () == 7 ); + assert ( std::all_of ( d3.begin (), d3.end (), [&val]( const T &item ){ return item == val; } )); + check_allocator ( d3, alloc2 ); + } + +int main() +{ +// This test is waiting on the resolution of LWG issue #2235 +// typedef test_allocator Alloc; +// typedef std::basic_string, Alloc> nstr; +// +// test ( nstr("fourteen"), Alloc(3), Alloc(4) ); +// test ( { nstr("1"), nstr("1"), nstr("2"), nstr("3"), nstr("5"), nstr("8")}, Alloc(6)); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.cons/default.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.cons/default.pass.cpp new file mode 100644 index 000000000000..0effac2fc142 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.cons/default.pass.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.cons + +// explicit dynarray(size_type c); +// dynarray(size_type c, const T& v); +// dynarray(initializer_list); +// dynarray(const dynarray& d); + +// ~dynarray(); + + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void test ( const std::initializer_list &vals ) { + typedef dynarray dynA; + + dynA d1 ( vals ); + assert ( d1.size () == vals.size() ); + assert ( std::equal ( vals.begin (), vals.end (), d1.begin (), d1.end ())); + } + + +template +void test ( const T &val ) { + typedef dynarray dynA; + + dynA d1 ( 4 ); + assert ( d1.size () == 4 ); + assert ( std::all_of ( d1.begin (), d1.end (), []( const T &item ){ return item == T(); } )); + + dynA d2 ( 7, val ); + assert ( d2.size () == 7 ); + assert ( std::all_of ( d2.begin (), d2.end (), [&val]( const T &item ){ return item == val; } )); + + dynA d3 ( d2 ); + assert ( d3.size () == 7 ); + assert ( std::all_of ( d3.begin (), d3.end (), [&val]( const T &item ){ return item == val; } )); + } + +void test_bad_length () { + try { dynarray ( std::numeric_limits::max() / sizeof ( int ) + 1 ); } + catch ( std::bad_array_length & ) { return ; } + assert ( false ); + } + +void test_bad_alloc () { + try { dynarray ( std::numeric_limits::max() / sizeof ( int ) - 1 ); } + catch ( std::bad_alloc & ) { return ; } + assert ( false ); + } + +int main() +{ +// test ( 14 ); // ints don't get default initialized + test ( 0 ); + test ( 14.0 ); + test> ( std::complex ( 14, 0 )); + test ( "fourteen" ); + + test ( { 1, 1, 2, 3, 5, 8 } ); + test ( { 1., 1., 2., 3., 5., 8. } ); + test ( { std::string("1"), std::string("1"), std::string("2"), std::string("3"), + std::string("5"), std::string("8")} ); + +// Make sure we don't pick up the Allocator version here + dynarray d1 ( 20, 3 ); + assert ( d1.size() == 20 ); + assert ( std::all_of ( d1.begin (), d1.end (), []( long item ){ return item == 3L; } )); + + test_bad_length (); + test_bad_alloc (); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.data/default.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.data/default.pass.cpp new file mode 100644 index 000000000000..b669f25948ed --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.data/default.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.data + +// T* data() noexcept; +// const T* data() const noexcept; + + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void dyn_test_const ( const dynarray &dyn ) { + const T *data = dyn.data (); + assert ( data != NULL ); + assert ( std::equal ( dyn.begin(), dyn.end(), data )); + } + +template +void dyn_test ( dynarray &dyn ) { + T *data = dyn.data (); + assert ( data != NULL ); + assert ( std::equal ( dyn.begin(), dyn.end(), data )); + } + + + +template +void test ( const T &val ) { + typedef dynarray dynA; + + dynA d1 ( 4 ); + dyn_test ( d1 ); + dyn_test_const ( d1 ); + + dynA d2 ( 7, val ); + dyn_test ( d2 ); + dyn_test_const ( d2 ); + } + +int main() +{ + test ( 14 ); + test ( 14.0 ); + test> ( std::complex ( 14, 0 )); + test ( "fourteen" ); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.mutate/default.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.mutate/default.pass.cpp new file mode 100644 index 000000000000..c57887ddaf94 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.mutate/default.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.data + +// void fill(const T& v); +// const T* data() const noexcept; + + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void test ( const T &val ) { + typedef dynarray dynA; + + dynA d1 ( 4 ); + d1.fill ( val ); + assert ( std::all_of ( d1.begin (), d1.end (), + [&val]( const T &item ){ return item == val; } )); + } + +int main() +{ + test ( 14 ); + test ( 14.0 ); + test> ( std::complex ( 14, 0 )); + test ( "fourteen" ); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/at.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/at.pass.cpp new file mode 100644 index 000000000000..4d77cf732758 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/at.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.overview + +// const_reference at(size_type n) const; +// reference at(size_type n); + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void dyn_at_fail ( dynarray &dyn, size_t sz ) { + try { dyn.at (sz); } + catch (const std::out_of_range &) { return; } + assert ( false ); + } + +template +void dyn_at_fail_const ( const dynarray &dyn, size_t sz ) { + try { dyn.at (sz); } + catch (const std::out_of_range &) { return; } + assert ( false ); + } + + +template +void dyn_test_const ( const dynarray &dyn, const std::initializer_list &vals ) { + const T *data = dyn.data (); + auto it = vals.begin (); + for ( size_t i = 0; i < dyn.size(); ++i, ++it ) { + assert ( data + i == &dyn.at(i)); + assert ( *it == dyn.at(i)); + } + + dyn_at_fail_const ( dyn, dyn.size ()); + dyn_at_fail_const ( dyn, 2*dyn.size ()); + dyn_at_fail_const ( dyn, size_t (-1)); + } + +template +void dyn_test ( dynarray &dyn, const std::initializer_list &vals ) { + T *data = dyn.data (); + auto it = vals.begin (); + for ( size_t i = 0; i < dyn.size(); ++i, ++it ) { + assert ( data + i == &dyn.at(i)); + assert ( *it == dyn.at(i)); + } + + dyn_at_fail ( dyn, dyn.size ()); + dyn_at_fail ( dyn, 2*dyn.size ()); + dyn_at_fail ( dyn, size_t (-1)); + } + + +template +void test ( std::initializer_list vals ) { + typedef dynarray dynA; + + dynA d1 ( vals ); + dyn_test ( d1, vals ); + dyn_test_const ( d1, vals ); + } + +int main() +{ + test ( { 1, 1, 2, 3, 5, 8 } ); + test ( { 1., 1., 2., 3., 5., 8. } ); + test ( { std::string("1"), std::string("1"), std::string("2"), std::string("3"), + std::string("5"), std::string("8")} ); + + test ( {} ); + test> ( {} ); + test ( {} ); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/begin_end.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/begin_end.pass.cpp new file mode 100644 index 000000000000..695e1aa9f14a --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/begin_end.pass.cpp @@ -0,0 +1,108 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.overview + + +// iterator begin() noexcept; +// const_iterator begin() const noexcept; +// const_iterator cbegin() const noexcept; +// iterator end() noexcept; +// const_iterator end() const noexcept; +// const_iterator cend() const noexcept; +// +// reverse_iterator rbegin() noexcept; +// const_reverse_iterator rbegin() const noexcept; +// const_reverse_iterator crbegin() const noexcept; +// reverse_iterator rend() noexcept; +// const_reverse_iterator rend() const noexcept; +// const_reverse_iterator crend() const noexcept; + + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void dyn_test_const ( const dynarray &dyn ) { + const T *data = dyn.data (); + assert ( data == &*dyn.begin ()); + assert ( data == &*dyn.cbegin ()); + + assert ( data + dyn.size() - 1 == &*dyn.rbegin ()); + assert ( data + dyn.size() - 1 == &*dyn.crbegin ()); + + assert ( dyn.size () == std::distance ( dyn.begin(), dyn.end())); + assert ( dyn.size () == std::distance ( dyn.cbegin(), dyn.cend())); + assert ( dyn.size () == std::distance ( dyn.rbegin(), dyn.rend())); + assert ( dyn.size () == std::distance ( dyn.crbegin(), dyn.crend())); + + assert ( dyn.begin () == dyn.cbegin ()); + assert ( &*dyn.begin () == &*dyn.cbegin ()); + assert ( dyn.rbegin () == dyn.crbegin ()); + assert ( &*dyn.rbegin () == &*dyn.crbegin ()); + assert ( dyn.end () == dyn.cend ()); + assert ( dyn.rend () == dyn.crend ()); + } + +template +void dyn_test ( dynarray &dyn ) { + T *data = dyn.data (); + assert ( data == &*dyn.begin ()); + assert ( data == &*dyn.cbegin ()); + + assert ( data + dyn.size() - 1 == &*dyn.rbegin ()); + assert ( data + dyn.size() - 1 == &*dyn.crbegin ()); + + assert ( dyn.size () == std::distance ( dyn.begin(), dyn.end())); + assert ( dyn.size () == std::distance ( dyn.cbegin(), dyn.cend())); + assert ( dyn.size () == std::distance ( dyn.rbegin(), dyn.rend())); + assert ( dyn.size () == std::distance ( dyn.crbegin(), dyn.crend())); + + assert ( dyn.begin () == dyn.cbegin ()); + assert ( &*dyn.begin () == &*dyn.cbegin ()); + assert ( dyn.rbegin () == dyn.crbegin ()); + assert ( &*dyn.rbegin () == &*dyn.crbegin ()); + assert ( dyn.end () == dyn.cend ()); + assert ( dyn.rend () == dyn.crend ()); + } + + +template +void test ( const T &val ) { + typedef dynarray dynA; + + dynA d1 ( 4 ); + dyn_test ( d1 ); + dyn_test_const ( d1 ); + + dynA d2 ( 7, val ); + dyn_test ( d2 ); + dyn_test_const ( d2 ); + } + +int main() +{ + test ( 14 ); + test ( 14.0 ); + test> ( std::complex ( 14, 0 )); + test ( "fourteen" ); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/capacity.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/capacity.pass.cpp new file mode 100644 index 000000000000..6d28eef1b057 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/capacity.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.overview + +// size_type size() const noexcept; +// size_type max_size() const noexcept; +// bool empty() const noexcept; + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void dyn_test ( const dynarray &dyn, size_t sz ) { + assert ( dyn.size () == sz ); + assert ( dyn.max_size () == sz ); + assert ( dyn.empty () == ( sz == 0 )); + } + +template +void test ( std::initializer_list vals ) { + typedef dynarray dynA; + + dynA d1 ( vals ); + dyn_test ( d1, vals.size ()); + } + +int main() +{ + test ( { 1, 1, 2, 3, 5, 8 } ); + test ( { 1., 1., 2., 3., 5., 8. } ); + test ( { std::string("1"), std::string("1"), std::string("2"), std::string("3"), + std::string("5"), std::string("8")} ); + + test ( {} ); + test> ( {} ); + test ( {} ); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/front_back.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/front_back.pass.cpp new file mode 100644 index 000000000000..e82aa64b98b6 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/front_back.pass.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.overview + +// reference front(); +// const_reference front() const; +// reference back(); +// const_reference back() const; + + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void dyn_test_const ( const dynarray &dyn ) { + const T *data = dyn.data (); + assert ( *data == dyn.front ()); + assert ( *(data + dyn.size() - 1 ) == dyn.back ()); + } + +template +void dyn_test ( dynarray &dyn ) { + T *data = dyn.data (); + assert ( *data == dyn.front ()); + assert ( *(data + dyn.size() - 1 ) == dyn.back ()); + } + + +template +void test ( const T &val ) { + typedef dynarray dynA; + + dynA d1 ( 4 ); + dyn_test ( d1 ); + dyn_test_const ( d1 ); + + dynA d2 ( 7, val ); + dyn_test ( d2 ); + dyn_test_const ( d2 ); + } + +int main() +{ + test ( 14 ); + test ( 14.0 ); + test> ( std::complex ( 14, 0 )); + test ( "fourteen" ); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/indexing.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/indexing.pass.cpp new file mode 100644 index 000000000000..7317a2023cb1 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.overview/indexing.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.overview + +// const_reference at(size_type n) const; +// reference at(size_type n); + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void dyn_test_const ( const dynarray &dyn, const std::initializer_list &vals ) { + const T *data = dyn.data (); + auto it = vals.begin (); + for ( size_t i = 0; i < dyn.size(); ++i, ++it ) { + assert ( data + i == &dyn[i]); + assert ( *it == dyn[i]); + } + } + +template +void dyn_test ( dynarray &dyn, const std::initializer_list &vals ) { + T *data = dyn.data (); + auto it = vals.begin (); + for ( size_t i = 0; i < dyn.size(); ++i, ++it ) { + assert ( data + i == &dyn[i]); + assert ( *it == dyn[i]); + } + } + + +template +void test ( std::initializer_list vals ) { + typedef dynarray dynA; + + dynA d1 ( vals ); + dyn_test ( d1, vals ); + dyn_test_const ( d1, vals ); + } + +int main() +{ + test ( { 1, 1, 2, 3, 5, 8 } ); + test ( { 1., 1., 2., 3., 5., 8. } ); + test ( { std::string("1"), std::string("1"), std::string("2"), std::string("3"), + std::string("5"), std::string("8")} ); + + test ( {} ); + test> ( {} ); + test ( {} ); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.traits/default.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.traits/default.pass.cpp new file mode 100644 index 000000000000..9b8240d4cd82 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.traits/default.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.data + +// template +// struct uses_allocator, Alloc> : true_type { }; + + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include "test_allocator.h" + +using std::experimental::dynarray; + +int main() +{ + static_assert ( std::uses_allocator, test_allocator>::value, "" ); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/dynarray.zero/default.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.zero/default.pass.cpp new file mode 100644 index 000000000000..93f3b18f192f --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/dynarray.zero/default.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// dynarray.zero + +// dynarray shall provide support for the special case of construction with a size of zero. +// In the case that the size is zero, begin() == end() == unique value. +// The return value of data() is unspecified. +// The effect of calling front() or back() for a zero-sized dynarray is undefined. + + + +#include <__config> + +#if _LIBCPP_STD_VER > 11 + +#include +#include + +#include +#include +#include + +using std::experimental::dynarray; + +template +void test ( ) { + typedef dynarray dynA; + + dynA d1 ( 0 ); + assert ( d1.size() == 0 ); + assert ( d1.begin() == d1.end ()); + } + +int main() +{ + test (); + test (); + test> (); + test (); +} +#else +int main() {} +#endif diff --git a/test/libcxx/experimental/containers/sequences/dynarray/nothing_to_do.pass.cpp b/test/libcxx/experimental/containers/sequences/dynarray/nothing_to_do.pass.cpp new file mode 100644 index 000000000000..b58f5c55b643 --- /dev/null +++ b/test/libcxx/experimental/containers/sequences/dynarray/nothing_to_do.pass.cpp @@ -0,0 +1,12 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main() +{ +} diff --git a/test/libcxx/experimental/utilities/ratio/header.ratio.synop/includes.pass.cpp b/test/libcxx/experimental/utilities/ratio/header.ratio.synop/includes.pass.cpp new file mode 100644 index 000000000000..db9026aebd84 --- /dev/null +++ b/test/libcxx/experimental/utilities/ratio/header.ratio.synop/includes.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// Test that is included. + +#include + +#if _LIBCPP_STD_VER > 11 +# ifndef _LIBCPP_RATIO +# error " must include " +# endif +#endif + +int main() +{ +} diff --git a/test/libcxx/experimental/utilities/ratio/version.pass.cpp b/test/libcxx/experimental/utilities/ratio/version.pass.cpp new file mode 100644 index 000000000000..8bc583fb6d94 --- /dev/null +++ b/test/libcxx/experimental/utilities/ratio/version.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() +{ +} diff --git a/test/libcxx/experimental/utilities/syserror/header.system_error.synop/includes.pass.cpp b/test/libcxx/experimental/utilities/syserror/header.system_error.synop/includes.pass.cpp new file mode 100644 index 000000000000..88c7458395d4 --- /dev/null +++ b/test/libcxx/experimental/utilities/syserror/header.system_error.synop/includes.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#if _LIBCPP_STD_VER > 11 +# ifndef _LIBCPP_SYSTEM_ERROR +# error " must include " +# endif +#endif + +int main() +{ +} diff --git a/test/libcxx/experimental/utilities/syserror/version.pass.cpp b/test/libcxx/experimental/utilities/syserror/version.pass.cpp new file mode 100644 index 000000000000..35f6a59c3876 --- /dev/null +++ b/test/libcxx/experimental/utilities/syserror/version.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() +{ +} diff --git a/test/libcxx/experimental/utilities/time/header.chrono.synop/includes.pass.cpp b/test/libcxx/experimental/utilities/time/header.chrono.synop/includes.pass.cpp new file mode 100644 index 000000000000..ad4a79105b0b --- /dev/null +++ b/test/libcxx/experimental/utilities/time/header.chrono.synop/includes.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#if _LIBCPP_STD_VER > 11 +# ifndef _LIBCPP_CHRONO +# error " must include " +# endif +#endif + +int main() +{ +} diff --git a/test/libcxx/experimental/utilities/time/version.pass.cpp b/test/libcxx/experimental/utilities/time/version.pass.cpp new file mode 100644 index 000000000000..be97466f37c0 --- /dev/null +++ b/test/libcxx/experimental/utilities/time/version.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() +{ +} diff --git a/test/libcxx/experimental/utilities/tuple/header.tuple.synop/includes.pass.cpp b/test/libcxx/experimental/utilities/tuple/header.tuple.synop/includes.pass.cpp new file mode 100644 index 000000000000..544ddfb269f2 --- /dev/null +++ b/test/libcxx/experimental/utilities/tuple/header.tuple.synop/includes.pass.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +int main() +{ +#if _LIBCPP_STD_VER > 11 +# ifndef _LIBCPP_TUPLE +# error " must include " +# endif +#endif /* _LIBCPP_STD_VER > 11 */ +} diff --git a/test/libcxx/experimental/utilities/tuple/version.pass.cpp b/test/libcxx/experimental/utilities/tuple/version.pass.cpp new file mode 100644 index 000000000000..5a3fd2e39647 --- /dev/null +++ b/test/libcxx/experimental/utilities/tuple/version.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() +{ +} diff --git a/test/libcxx/selftest/not_test.sh.cpp b/test/libcxx/selftest/not_test.sh.cpp new file mode 100644 index 000000000000..5b8348f0eecd --- /dev/null +++ b/test/libcxx/selftest/not_test.sh.cpp @@ -0,0 +1,17 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// RUN: %build +// RUN: not %run + +int main() +{ + return 1; +} diff --git a/test/libcxx/selftest/test.fail.cpp b/test/libcxx/selftest/test.fail.cpp new file mode 100644 index 000000000000..2ad608bab260 --- /dev/null +++ b/test/libcxx/selftest/test.fail.cpp @@ -0,0 +1,11 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#error This test should not compile. diff --git a/test/libcxx/selftest/test.pass.cpp b/test/libcxx/selftest/test.pass.cpp new file mode 100644 index 000000000000..9a59227abdd9 --- /dev/null +++ b/test/libcxx/selftest/test.pass.cpp @@ -0,0 +1,13 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main() +{ +} diff --git a/test/libcxx/selftest/test.sh.cpp b/test/libcxx/selftest/test.sh.cpp new file mode 100644 index 000000000000..14dc2db8018b --- /dev/null +++ b/test/libcxx/selftest/test.sh.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// RUN: %build +// RUN: %run + +int main() +{ +} diff --git a/test/libcxx/selftest/test_macros.pass.cpp b/test/libcxx/selftest/test_macros.pass.cpp new file mode 100644 index 000000000000..2c8ed4f454a7 --- /dev/null +++ b/test/libcxx/selftest/test_macros.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Test the "test_macros.h" header. +#include "test_macros.h" + +#ifndef TEST_STD_VER +#error TEST_STD_VER must be defined +#endif + +#ifndef TEST_DECLTYPE +#error TEST_DECLTYPE must be defined +#endif + +#ifndef TEST_NOEXCEPT +#error TEST_NOEXCEPT must be defined +#endif + +#ifndef TEST_STATIC_ASSERT +#error TEST_STATIC_ASSERT must be defined +#endif + +template +struct is_same { enum { value = 0 }; }; + +template +struct is_same { enum { value = 1 }; }; + +int foo() { return 0; } + +void test_noexcept() TEST_NOEXCEPT +{ +} + +void test_decltype() +{ + typedef TEST_DECLTYPE(foo()) MyType; + TEST_STATIC_ASSERT((is_same::value), "is same"); +} + +void test_static_assert() +{ + TEST_STATIC_ASSERT((is_same::value), "is same"); + TEST_STATIC_ASSERT((!is_same::value), "not same"); +} + +int main() +{ + test_noexcept(); + test_decltype(); + test_static_assert(); +} diff --git a/test/libcxx/test/__init__.py b/test/libcxx/test/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/libcxx/test/config.py b/test/libcxx/test/config.py new file mode 100644 index 000000000000..09fbf66dbba0 --- /dev/null +++ b/test/libcxx/test/config.py @@ -0,0 +1,709 @@ +import importlib +import locale +import os +import platform +import pkgutil +import re +import shlex +import sys + +import lit.Test # pylint: disable=import-error,no-name-in-module +import lit.util # pylint: disable=import-error,no-name-in-module + +from libcxx.test.format import LibcxxTestFormat +from libcxx.compiler import CXXCompiler +from libcxx.test.executor import * +from libcxx.test.tracing import * + +def loadSiteConfig(lit_config, config, param_name, env_name): + # We haven't loaded the site specific configuration (the user is + # probably trying to run on a test file directly, and either the site + # configuration hasn't been created by the build system, or we are in an + # out-of-tree build situation). + site_cfg = lit_config.params.get(param_name, + os.environ.get(env_name)) + if not site_cfg: + lit_config.warning('No site specific configuration file found!' + ' Running the tests in the default configuration.') + elif not os.path.isfile(site_cfg): + lit_config.fatal( + "Specified site configuration file does not exist: '%s'" % + site_cfg) + else: + lit_config.note('using site specific configuration at %s' % site_cfg) + ld_fn = lit_config.load_config + + # Null out the load_config function so that lit.site.cfg doesn't + # recursively load a config even if it tries. + # TODO: This is one hell of a hack. Fix it. + def prevent_reload_fn(*args, **kwargs): + pass + lit_config.load_config = prevent_reload_fn + ld_fn(config, site_cfg) + lit_config.load_config = ld_fn + + +class Configuration(object): + # pylint: disable=redefined-outer-name + def __init__(self, lit_config, config): + self.lit_config = lit_config + self.config = config + self.cxx = None + self.libcxx_src_root = None + self.libcxx_obj_root = None + self.cxx_library_root = None + self.abi_library_root = None + self.env = {} + self.use_target = False + self.use_system_cxx_lib = False + self.use_clang_verify = False + self.long_tests = None + self.execute_external = False + + def get_lit_conf(self, name, default=None): + val = self.lit_config.params.get(name, None) + if val is None: + val = getattr(self.config, name, None) + if val is None: + val = default + return val + + def get_lit_bool(self, name, default=None): + conf = self.get_lit_conf(name) + if conf is None: + return default + if conf.lower() in ('1', 'true'): + return True + if conf.lower() in ('', '0', 'false'): + return False + self.lit_config.fatal( + "parameter '{}' should be true or false".format(name)) + + def configure(self): + self.configure_executor() + self.configure_target_info() + self.configure_cxx() + self.configure_triple() + self.configure_src_root() + self.configure_obj_root() + self.configure_cxx_library_root() + self.configure_use_system_cxx_lib() + self.configure_use_clang_verify() + self.configure_execute_external() + self.configure_ccache() + self.configure_compile_flags() + self.configure_link_flags() + self.configure_env() + self.configure_color_diagnostics() + self.configure_debug_mode() + self.configure_warnings() + self.configure_sanitizer() + self.configure_coverage() + self.configure_substitutions() + self.configure_features() + + def print_config_info(self): + # Print the final compile and link flags. + self.lit_config.note('Using compiler: %s' % self.cxx.path) + self.lit_config.note('Using flags: %s' % self.cxx.flags) + self.lit_config.note('Using compile flags: %s' + % self.cxx.compile_flags) + self.lit_config.note('Using link flags: %s' % self.cxx.link_flags) + # Print as list to prevent "set([...])" from being printed. + self.lit_config.note('Using available_features: %s' % + list(self.config.available_features)) + self.lit_config.note('Using environment: %r' % self.env) + + def get_test_format(self): + return LibcxxTestFormat( + self.cxx, + self.use_clang_verify, + self.execute_external, + self.executor, + exec_env=self.env) + + def configure_executor(self): + exec_str = self.get_lit_conf('executor', "None") + te = eval(exec_str) + if te: + self.lit_config.note("Using executor: %r" % exec_str) + if self.lit_config.useValgrind: + # We have no way of knowing where in the chain the + # ValgrindExecutor is supposed to go. It is likely + # that the user wants it at the end, but we have no + # way of getting at that easily. + selt.lit_config.fatal("Cannot infer how to create a Valgrind " + " executor.") + else: + te = LocalExecutor() + if self.lit_config.useValgrind: + te = ValgrindExecutor(self.lit_config.valgrindArgs, te) + self.executor = te + + def configure_target_info(self): + default = "libcxx.test.target_info.LocalTI" + info_str = self.get_lit_conf('target_info', default) + mod_path, _, info = info_str.rpartition('.') + mod = importlib.import_module(mod_path) + self.target_info = getattr(mod, info)() + if info_str != default: + self.lit_config.note("inferred target_info as: %r" % info_str) + + def configure_cxx(self): + # Gather various compiler parameters. + cxx = self.get_lit_conf('cxx_under_test') + + # If no specific cxx_under_test was given, attempt to infer it as + # clang++. + if cxx is None: + clangxx = lit.util.which('clang++', + self.config.environment['PATH']) + if clangxx: + cxx = clangxx + self.lit_config.note( + "inferred cxx_under_test as: %r" % cxx) + if not cxx: + self.lit_config.fatal('must specify user parameter cxx_under_test ' + '(e.g., --param=cxx_under_test=clang++)') + self.cxx = CXXCompiler(cxx) + cxx_type = self.cxx.type + if cxx_type is not None: + assert self.cxx.version is not None + maj_v, min_v, _ = self.cxx.version + self.config.available_features.add(cxx_type) + self.config.available_features.add('%s-%s.%s' % ( + cxx_type, maj_v, min_v)) + + def configure_src_root(self): + self.libcxx_src_root = self.get_lit_conf( + 'libcxx_src_root', os.path.dirname(self.config.test_source_root)) + + def configure_obj_root(self): + self.libcxx_obj_root = self.get_lit_conf('libcxx_obj_root') + + def configure_cxx_library_root(self): + self.cxx_library_root = self.get_lit_conf('cxx_library_root', + self.libcxx_obj_root) + + def configure_use_system_cxx_lib(self): + # This test suite supports testing against either the system library or + # the locally built one; the former mode is useful for testing ABI + # compatibility between the current headers and a shipping dynamic + # library. + self.use_system_cxx_lib = self.get_lit_bool('use_system_cxx_lib') + if self.use_system_cxx_lib is None: + # Default to testing against the locally built libc++ library. + self.use_system_cxx_lib = False + self.lit_config.note( + "inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib) + + def configure_use_clang_verify(self): + '''If set, run clang with -verify on failing tests.''' + self.use_clang_verify = self.get_lit_bool('use_clang_verify') + if self.use_clang_verify is None: + # NOTE: We do not test for the -verify flag directly because + # -verify will always exit with non-zero on an empty file. + self.use_clang_verify = self.cxx.hasCompileFlag( + ['-Xclang', '-verify-ignore-unexpected']) + self.lit_config.note( + "inferred use_clang_verify as: %r" % self.use_clang_verify) + + def configure_execute_external(self): + # Choose between lit's internal shell pipeline runner and a real shell. + # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the + # default value. Otherwise we default to internal on Windows and + # external elsewhere, as bash on Windows is usually very slow. + use_lit_shell_default = os.environ.get('LIT_USE_INTERNAL_SHELL') + if use_lit_shell_default is not None: + use_lit_shell_default = use_lit_shell_default != '0' + else: + use_lit_shell_default = sys.platform == 'win32' + # Check for the command line parameter using the default value if it is + # not present. + use_lit_shell = self.get_lit_bool('use_lit_shell', + use_lit_shell_default) + self.execute_external = not use_lit_shell + + def configure_ccache(self): + use_ccache_default = os.environ.get('LIBCXX_USE_CCACHE') is not None + use_ccache = self.get_lit_bool('use_ccache', use_ccache_default) + if use_ccache: + self.cxx.use_ccache = True + self.lit_config.note('enabling ccache') + + def configure_features(self): + additional_features = self.get_lit_conf('additional_features') + if additional_features: + for f in additional_features.split(','): + self.config.available_features.add(f.strip()) + + # Figure out which of the required locales we support + locales = { + 'Darwin': { + 'en_US.UTF-8': 'en_US.UTF-8', + 'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2', + 'fr_FR.UTF-8': 'fr_FR.UTF-8', + 'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1', + 'ru_RU.UTF-8': 'ru_RU.UTF-8', + 'zh_CN.UTF-8': 'zh_CN.UTF-8', + }, + 'FreeBSD': { + 'en_US.UTF-8': 'en_US.UTF-8', + 'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2', + 'fr_FR.UTF-8': 'fr_FR.UTF-8', + 'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1', + 'ru_RU.UTF-8': 'ru_RU.UTF-8', + 'zh_CN.UTF-8': 'zh_CN.UTF-8', + }, + 'Linux': { + 'en_US.UTF-8': 'en_US.UTF-8', + 'cs_CZ.ISO8859-2': 'cs_CZ.ISO-8859-2', + 'fr_FR.UTF-8': 'fr_FR.UTF-8', + 'fr_CA.ISO8859-1': 'fr_CA.ISO-8859-1', + 'ru_RU.UTF-8': 'ru_RU.UTF-8', + 'zh_CN.UTF-8': 'zh_CN.UTF-8', + }, + 'Windows': { + 'en_US.UTF-8': 'English_United States.1252', + 'cs_CZ.ISO8859-2': 'Czech_Czech Republic.1250', + 'fr_FR.UTF-8': 'French_France.1252', + 'fr_CA.ISO8859-1': 'French_Canada.1252', + 'ru_RU.UTF-8': 'Russian_Russia.1251', + 'zh_CN.UTF-8': 'Chinese_China.936', + }, + } + + target_system = self.target_info.system() + target_platform = self.target_info.platform() + + if target_system in locales: + default_locale = locale.setlocale(locale.LC_ALL) + for feature, loc in locales[target_system].items(): + try: + locale.setlocale(locale.LC_ALL, loc) + self.config.available_features.add( + 'locale.{0}'.format(feature)) + except locale.Error: + self.lit_config.warning('The locale {0} is not supported by ' + 'your platform. Some tests will be ' + 'unsupported.'.format(loc)) + locale.setlocale(locale.LC_ALL, default_locale) + else: + # Warn that the user doesn't get any free XFAILs for locale issues + self.lit_config.warning("No locales entry for target_system: %s" % + target_system) + + # Write an "available feature" that combines the triple when + # use_system_cxx_lib is enabled. This is so that we can easily write + # XFAIL markers for tests that are known to fail with versions of + # libc++ as were shipped with a particular triple. + if self.use_system_cxx_lib: + self.config.available_features.add( + 'with_system_cxx_lib=%s' % self.config.target_triple) + + # Insert the platform name into the available features as a lower case. + self.config.available_features.add(target_platform) + + # Some linux distributions have different locale data than others. + # Insert the distributions name and name-version into the available + # features to allow tests to XFAIL on them. + if target_platform == 'linux': + name = self.target_info.platform_name() + ver = self.target_info.platform_ver() + if name: + self.config.available_features.add(name) + if name and ver: + self.config.available_features.add('%s-%s' % (name, ver)) + + # Simulator testing can take a really long time for some of these tests + # so add a feature check so we can REQUIRES: long_tests in them + self.long_tests = self.get_lit_bool('long_tests') + if self.long_tests is None: + # Default to running long tests. + self.long_tests = True + self.lit_config.note( + "inferred long_tests as: %r" % self.long_tests) + + if self.long_tests: + self.config.available_features.add('long_tests') + + # Run a compile test for the -fsized-deallocation flag. This is needed + # in test/std/language.support/support.dynamic/new.delete + if self.cxx.hasCompileFlag('-fsized-deallocation'): + self.config.available_features.add('fsized-deallocation') + + def configure_compile_flags(self): + no_default_flags = self.get_lit_bool('no_default_flags', False) + if not no_default_flags: + self.configure_default_compile_flags() + # Configure extra flags + compile_flags_str = self.get_lit_conf('compile_flags', '') + self.cxx.compile_flags += shlex.split(compile_flags_str) + + def configure_default_compile_flags(self): + # Try and get the std version from the command line. Fall back to + # default given in lit.site.cfg is not present. If default is not + # present then force c++11. + std = self.get_lit_conf('std', 'c++11') + self.cxx.compile_flags += ['-std={0}'.format(std)] + self.config.available_features.add(std) + # Configure include paths + self.cxx.compile_flags += ['-nostdinc++'] + self.configure_compile_flags_header_includes() + if self.target_info.platform() == 'linux': + self.cxx.compile_flags += ['-D__STDC_FORMAT_MACROS', + '-D__STDC_LIMIT_MACROS', + '-D__STDC_CONSTANT_MACROS'] + # Configure feature flags. + self.configure_compile_flags_exceptions() + self.configure_compile_flags_rtti() + self.configure_compile_flags_no_global_filesystem_namespace() + self.configure_compile_flags_no_stdin() + self.configure_compile_flags_no_stdout() + enable_32bit = self.get_lit_bool('enable_32bit', False) + if enable_32bit: + self.cxx.flags += ['-m32'] + # Configure threading features. + enable_threads = self.get_lit_bool('enable_threads', True) + enable_monotonic_clock = self.get_lit_bool('enable_monotonic_clock', + True) + if not enable_threads: + self.configure_compile_flags_no_threads() + if not enable_monotonic_clock: + self.configure_compile_flags_no_monotonic_clock() + elif not enable_monotonic_clock: + self.lit_config.fatal('enable_monotonic_clock cannot be false when' + ' enable_threads is true.') + self.configure_compile_flags_no_thread_unsafe_c_functions() + + # Use verbose output for better errors + self.cxx.flags += ['-v'] + sysroot = self.get_lit_conf('sysroot') + if sysroot: + self.cxx.flags += ['--sysroot', sysroot] + gcc_toolchain = self.get_lit_conf('gcc_toolchain') + if gcc_toolchain: + self.cxx.flags += ['-gcc-toolchain', gcc_toolchain] + if self.use_target: + self.cxx.flags += ['-target', self.config.target_triple] + + def configure_compile_flags_header_includes(self): + support_path = os.path.join(self.libcxx_src_root, 'test/support') + self.cxx.compile_flags += ['-I' + support_path] + self.cxx.compile_flags += ['-include', os.path.join(support_path, 'nasty_macros.hpp')] + libcxx_headers = self.get_lit_conf( + 'libcxx_headers', os.path.join(self.libcxx_src_root, 'include')) + if not os.path.isdir(libcxx_headers): + self.lit_config.fatal("libcxx_headers='%s' is not a directory." + % libcxx_headers) + self.cxx.compile_flags += ['-I' + libcxx_headers] + + def configure_compile_flags_exceptions(self): + enable_exceptions = self.get_lit_bool('enable_exceptions', True) + if not enable_exceptions: + self.config.available_features.add('libcpp-no-exceptions') + self.cxx.compile_flags += ['-fno-exceptions'] + + def configure_compile_flags_rtti(self): + enable_rtti = self.get_lit_bool('enable_rtti', True) + if not enable_rtti: + self.config.available_features.add('libcpp-no-rtti') + self.cxx.compile_flags += ['-fno-rtti', '-D_LIBCPP_NO_RTTI'] + + def configure_compile_flags_no_global_filesystem_namespace(self): + enable_global_filesystem_namespace = self.get_lit_bool( + 'enable_global_filesystem_namespace', True) + if not enable_global_filesystem_namespace: + self.config.available_features.add( + 'libcpp-has-no-global-filesystem-namespace') + self.cxx.compile_flags += [ + '-D_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE'] + + def configure_compile_flags_no_stdin(self): + enable_stdin = self.get_lit_bool('enable_stdin', True) + if not enable_stdin: + self.config.available_features.add('libcpp-has-no-stdin') + self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_STDIN'] + + def configure_compile_flags_no_stdout(self): + enable_stdout = self.get_lit_bool('enable_stdout', True) + if not enable_stdout: + self.config.available_features.add('libcpp-has-no-stdout') + self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_STDOUT'] + + def configure_compile_flags_no_threads(self): + self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_THREADS'] + self.config.available_features.add('libcpp-has-no-threads') + + def configure_compile_flags_no_thread_unsafe_c_functions(self): + enable_thread_unsafe_c_functions = self.get_lit_bool( + 'enable_thread_unsafe_c_functions', True) + if not enable_thread_unsafe_c_functions: + self.cxx.compile_flags += [ + '-D_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS'] + self.config.available_features.add( + 'libcpp-has-no-thread-unsafe-c-functions') + + def configure_compile_flags_no_monotonic_clock(self): + self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_MONOTONIC_CLOCK'] + self.config.available_features.add('libcpp-has-no-monotonic-clock') + + def configure_link_flags(self): + no_default_flags = self.get_lit_bool('no_default_flags', False) + if not no_default_flags: + self.cxx.link_flags += ['-nodefaultlibs'] + + # Configure library path + self.configure_link_flags_cxx_library_path() + self.configure_link_flags_abi_library_path() + + # Configure libraries + self.configure_link_flags_cxx_library() + self.configure_link_flags_abi_library() + self.configure_extra_library_flags() + + link_flags_str = self.get_lit_conf('link_flags', '') + self.cxx.link_flags += shlex.split(link_flags_str) + + def configure_link_flags_cxx_library_path(self): + libcxx_library = self.get_lit_conf('libcxx_library') + # Configure libc++ library paths. + if libcxx_library is not None: + # Check that the given value for libcxx_library is valid. + if not os.path.isfile(libcxx_library): + self.lit_config.fatal( + "libcxx_library='%s' is not a valid file." % + libcxx_library) + if self.use_system_cxx_lib: + self.lit_config.fatal( + "Conflicting options: 'libcxx_library' cannot be used " + "with 'use_system_cxx_lib=true'") + self.cxx.link_flags += ['-Wl,-rpath,' + + os.path.dirname(libcxx_library)] + elif not self.use_system_cxx_lib and self.cxx_library_root: + self.cxx.link_flags += ['-L' + self.cxx_library_root, + '-Wl,-rpath,' + self.cxx_library_root] + + def configure_link_flags_abi_library_path(self): + # Configure ABI library paths. + self.abi_library_root = self.get_lit_conf('abi_library_path') + if self.abi_library_root: + self.cxx.link_flags += ['-L' + self.abi_library_root, + '-Wl,-rpath,' + self.abi_library_root] + + def configure_link_flags_cxx_library(self): + libcxx_library = self.get_lit_conf('libcxx_library') + if libcxx_library: + self.cxx.link_flags += [libcxx_library] + else: + self.cxx.link_flags += ['-lc++'] + + def configure_link_flags_abi_library(self): + cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi') + if cxx_abi == 'libstdc++': + self.cxx.link_flags += ['-lstdc++'] + elif cxx_abi == 'libsupc++': + self.cxx.link_flags += ['-lsupc++'] + elif cxx_abi == 'libcxxabi': + # Don't link libc++abi explicitly on OS X because the symbols + # should be available in libc++ directly. + if self.target_info.platform() != 'darwin': + self.cxx.link_flags += ['-lc++abi'] + elif cxx_abi == 'libcxxrt': + self.cxx.link_flags += ['-lcxxrt'] + elif cxx_abi == 'none': + pass + else: + self.lit_config.fatal( + 'C++ ABI setting %s unsupported for tests' % cxx_abi) + + def configure_extra_library_flags(self): + enable_threads = self.get_lit_bool('enable_threads', True) + llvm_unwinder = self.get_lit_bool('llvm_unwinder', False) + target_platform = self.target_info.platform() + if target_platform == 'darwin': + self.cxx.link_flags += ['-lSystem'] + elif target_platform == 'linux': + if not llvm_unwinder: + self.cxx.link_flags += ['-lgcc_eh'] + self.cxx.link_flags += ['-lc', '-lm'] + if enable_threads: + self.cxx.link_flags += ['-lpthread'] + self.cxx.link_flags += ['-lrt'] + if llvm_unwinder: + self.cxx.link_flags += ['-lunwind', '-ldl'] + else: + self.cxx.link_flags += ['-lgcc_s'] + elif target_platform.startswith('freebsd'): + self.cxx.link_flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lcxxrt'] + else: + self.lit_config.fatal("unrecognized system: %r" % target_platform) + + def configure_color_diagnostics(self): + use_color = self.get_lit_conf('color_diagnostics') + if use_color is None: + use_color = os.environ.get('LIBCXX_COLOR_DIAGNOSTICS') + if use_color is None: + return + if use_color != '': + self.lit_config.fatal('Invalid value for color_diagnostics "%s".' + % use_color) + color_flag = '-fdiagnostics-color=always' + # Check if the compiler supports the color diagnostics flag. Issue a + # warning if it does not since color diagnostics have been requested. + if not self.cxx.hasCompileFlag(color_flag): + self.lit_config.warning( + 'color diagnostics have been requested but are not supported ' + 'by the compiler') + else: + self.cxx.flags += [color_flag] + + def configure_debug_mode(self): + debug_level = self.get_lit_conf('debug_level', None) + if not debug_level: + return + if debug_level not in ['0', '1']: + self.lit_config.fatal('Invalid value for debug_level "%s".' + % debug_level) + self.cxx.compile_flags += ['-D_LIBCPP_DEBUG=%s' % debug_level] + + def configure_warnings(self): + enable_warnings = self.get_lit_bool('enable_warnings', False) + if enable_warnings: + self.cxx.compile_flags += ['-Wsystem-headers', '-Wall', '-Werror'] + if ('clang' in self.config.available_features or + 'apple-clang' in self.config.available_features): + self.cxx.compile_flags += ['-Wno-user-defined-literals'] + + def configure_sanitizer(self): + san = self.get_lit_conf('use_sanitizer', '').strip() + if san: + # Search for llvm-symbolizer along the compiler path first + # and then along the PATH env variable. + symbolizer_search_paths = os.environ.get('PATH', '') + cxx_path = lit.util.which(self.cxx.path) + if cxx_path is not None: + symbolizer_search_paths = ( + os.path.dirname(cxx_path) + + os.pathsep + symbolizer_search_paths) + llvm_symbolizer = lit.util.which('llvm-symbolizer', + symbolizer_search_paths) + # Setup the sanitizer compile flags + self.cxx.flags += ['-g', '-fno-omit-frame-pointer'] + if self.target_info.platform() == 'linux': + self.cxx.link_flags += ['-ldl'] + if san == 'Address': + self.cxx.flags += ['-fsanitize=address'] + if llvm_symbolizer is not None: + self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer + self.config.available_features.add('asan') + self.config.available_features.add('sanitizer-new-delete') + elif san == 'Memory' or san == 'MemoryWithOrigins': + self.cxx.flags += ['-fsanitize=memory'] + if san == 'MemoryWithOrigins': + self.cxx.compile_flags += [ + '-fsanitize-memory-track-origins'] + if llvm_symbolizer is not None: + self.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer + self.config.available_features.add('msan') + self.config.available_features.add('sanitizer-new-delete') + elif san == 'Undefined': + self.cxx.flags += ['-fsanitize=undefined', + '-fno-sanitize=vptr,function', + '-fno-sanitize-recover'] + self.cxx.compile_flags += ['-O3'] + self.config.available_features.add('ubsan') + elif san == 'Thread': + self.cxx.flags += ['-fsanitize=thread'] + self.config.available_features.add('tsan') + self.config.available_features.add('sanitizer-new-delete') + else: + self.lit_config.fatal('unsupported value for ' + 'use_sanitizer: {0}'.format(san)) + + def configure_coverage(self): + self.generate_coverage = self.get_lit_bool('generate_coverage', False) + if self.generate_coverage: + self.cxx.flags += ['-g', '--coverage'] + self.cxx.compile_flags += ['-O0'] + + def configure_substitutions(self): + sub = self.config.substitutions + # Configure compiler substitions + sub.append(('%cxx', self.cxx.path)) + # Configure flags substitutions + flags_str = ' '.join(self.cxx.flags) + compile_flags_str = ' '.join(self.cxx.compile_flags) + link_flags_str = ' '.join(self.cxx.link_flags) + all_flags = '%s %s %s' % (flags_str, compile_flags_str, link_flags_str) + sub.append(('%flags', flags_str)) + sub.append(('%compile_flags', compile_flags_str)) + sub.append(('%link_flags', link_flags_str)) + sub.append(('%all_flags', all_flags)) + # Add compile and link shortcuts + compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str + + compile_flags_str) + link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str + + link_flags_str) + assert type(link_str) is str + build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags + sub.append(('%compile', compile_str)) + sub.append(('%link', link_str)) + sub.append(('%build', build_str)) + # Configure exec prefix substitutions. + exec_env_str = 'env ' if len(self.env) != 0 else '' + for k, v in self.env.items(): + exec_env_str += ' %s=%s' % (k, v) + # Configure run env substitution. + exec_str = '' + if self.lit_config.useValgrind: + exec_str = ' '.join(self.lit_config.valgrindArgs) + exec_env_str + sub.append(('%exec', exec_str)) + # Configure run shortcut + sub.append(('%run', exec_str + ' %t.exe')) + # Configure not program substitions + not_py = os.path.join(self.libcxx_src_root, 'utils', 'not', 'not.py') + not_str = '%s %s' % (sys.executable, not_py) + sub.append(('not', not_str)) + + def configure_triple(self): + # Get or infer the target triple. + self.config.target_triple = self.get_lit_conf('target_triple') + self.use_target = bool(self.config.target_triple) + # If no target triple was given, try to infer it from the compiler + # under test. + if not self.use_target: + target_triple = self.cxx.getTriple() + # Drop sub-major version components from the triple, because the + # current XFAIL handling expects exact matches for feature checks. + # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14 + # The 5th group handles triples greater than 3 parts + # (ex x86_64-pc-linux-gnu). + target_triple = re.sub(r'([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)', + r'\1-\2-\3\5', target_triple) + # linux-gnu is needed in the triple to properly identify linuxes + # that use GLIBC. Handle redhat and opensuse triples as special + # cases and append the missing `-gnu` portion. + if (target_triple.endswith('redhat-linux') or + target_triple.endswith('suse-linux')): + target_triple += '-gnu' + self.config.target_triple = target_triple + self.lit_config.note( + "inferred target_triple as: %r" % self.config.target_triple) + + def configure_env(self): + if self.target_info.platform() == 'darwin': + library_paths = [] + # Configure the library path for libc++ + libcxx_library = self.get_lit_conf('libcxx_library') + if self.use_system_cxx_lib: + pass + elif libcxx_library: + library_paths += [os.path.dirname(libcxx_library)] + elif self.cxx_library_root: + library_paths += [self.cxx_library_root] + # Configure the abi library path + if self.abi_library_root: + library_paths += [self.abi_library_root] + if library_paths: + self.env['DYLD_LIBRARY_PATH'] = ':'.join(library_paths) diff --git a/test/libcxx/test/executor.py b/test/libcxx/test/executor.py new file mode 100644 index 000000000000..f0356ceca784 --- /dev/null +++ b/test/libcxx/test/executor.py @@ -0,0 +1,191 @@ +import os + +from libcxx.test import tracing + +from lit.util import executeCommand # pylint: disable=import-error + + +class Executor(object): + def run(self, exe_path, cmd, local_cwd, file_deps=None, env=None): + """Execute a command. + Be very careful not to change shared state in this function. + Executor objects are shared between python processes in `lit -jN`. + Args: + exe_path: str: Local path to the executable to be run + cmd: [str]: subprocess.call style command + local_cwd: str: Local path to the working directory + file_deps: [str]: Files required by the test + env: {str: str}: Environment variables to execute under + Returns: + cmd, out, err, exitCode + """ + raise NotImplementedError + + +class LocalExecutor(Executor): + def __init__(self): + super(LocalExecutor, self).__init__() + + def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None): + cmd = cmd or [exe_path] + env_cmd = [] + if env: + env_cmd += ['env'] + env_cmd += ['%s=%s' % (k, v) for k, v in env.items()] + if work_dir == '.': + work_dir = os.getcwd() + out, err, rc = executeCommand(env_cmd + cmd, cwd=work_dir) + return (env_cmd + cmd, out, err, rc) + + +class PrefixExecutor(Executor): + """Prefix an executor with some other command wrapper. + + Most useful for setting ulimits on commands, or running an emulator like + qemu and valgrind. + """ + def __init__(self, commandPrefix, chain): + super(PrefixExecutor, self).__init__() + + self.commandPrefix = commandPrefix + self.chain = chain + + def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None): + cmd = cmd or [exe_path] + return self.chain.run(exe_path, self.commandPrefix + cmd, work_dir, + file_deps, env=env) + + +class PostfixExecutor(Executor): + """Postfix an executor with some args.""" + def __init__(self, commandPostfix, chain): + super(PostfixExecutor, self).__init__() + + self.commandPostfix = commandPostfix + self.chain = chain + + def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None): + cmd = cmd or [exe_path] + return self.chain.run(cmd + self.commandPostfix, work_dir, file_deps, + env=env) + + + +class TimeoutExecutor(PrefixExecutor): + """Execute another action under a timeout. + + Deprecated. http://reviews.llvm.org/D6584 adds timeouts to LIT. + """ + def __init__(self, duration, chain): + super(TimeoutExecutor, self).__init__( + ['timeout', duration], chain) + + +class RemoteExecutor(Executor): + def __init__(self): + self.local_run = executeCommand + + def remote_temp_dir(self): + return self._remote_temp(True) + + def remote_temp_file(self): + return self._remote_temp(False) + + def _remote_temp(self, is_dir): + raise NotImplementedError() + + def copy_in(self, local_srcs, remote_dsts): + # This could be wrapped up in a tar->scp->untar for performance + # if there are lots of files to be copied/moved + for src, dst in zip(local_srcs, remote_dsts): + self._copy_in_file(src, dst) + + def _copy_in_file(self, src, dst): + raise NotImplementedError() + + def delete_remote(self, remote): + try: + self._execute_command_remote(['rm', '-rf', remote]) + except OSError: + # TODO: Log failure to delete? + pass + + def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None): + target_exe_path = None + target_cwd = None + try: + target_cwd = self.remote_temp_dir() + target_exe_path = os.path.join(target_cwd, 'libcxx_test.exe') + if cmd: + # Replace exe_path with target_exe_path. + cmd = [c if c != exe_path else target_exe_path for c in cmd] + else: + cmd = [target_exe_path] + + srcs = [exe_path] + dsts = [target_exe_path] + if file_deps is not None: + dev_paths = [os.path.join(target_cwd, os.path.basename(f)) + for f in file_deps] + srcs.extend(file_deps) + dsts.extend(dev_paths) + self.copy_in(srcs, dsts) + # TODO(jroelofs): capture the copy_in and delete_remote commands, + # and conjugate them with '&&'s around the first tuple element + # returned here: + return self._execute_command_remote(cmd, target_cwd, env) + finally: + if target_cwd: + self.delete_remote(target_cwd) + + def _execute_command_remote(self, cmd, remote_work_dir='.', env=None): + raise NotImplementedError() + + +class SSHExecutor(RemoteExecutor): + def __init__(self, host, username=None): + super(SSHExecutor, self).__init__() + + self.user_prefix = username + '@' if username else '' + self.host = host + self.scp_command = 'scp' + self.ssh_command = 'ssh' + + # TODO(jroelofs): switch this on some -super-verbose-debug config flag + if False: + self.local_run = tracing.trace_function( + self.local_run, log_calls=True, log_results=True, + label='ssh_local') + + def _remote_temp(self, is_dir): + # TODO: detect what the target system is, and use the correct + # mktemp command for it. (linux and darwin differ here, and I'm + # sure windows has another way to do it) + + # Not sure how to do suffix on osx yet + dir_arg = '-d' if is_dir else '' + cmd = 'mktemp -q {} /tmp/libcxx.XXXXXXXXXX'.format(dir_arg) + temp_path, err, exitCode = self._execute_command_remote([cmd]) + temp_path = temp_path.strip() + if exitCode != 0: + raise RuntimeError(err) + return temp_path + + def _copy_in_file(self, src, dst): + scp = self.scp_command + remote = self.host + remote = self.user_prefix + remote + cmd = [scp, '-p', src, remote + ':' + dst] + self.local_run(cmd) + + def _execute_command_remote(self, cmd, remote_work_dir='.', env=None): + remote = self.user_prefix + self.host + ssh_cmd = [self.ssh_command, '-oBatchMode=yes', remote] + if env: + env_cmd = ['env'] + ['%s=%s' % (k, v) for k, v in env.items()] + else: + env_cmd = [] + remote_cmd = ' '.join(env_cmd + cmd) + if remote_work_dir != '.': + remote_cmd = 'cd ' + remote_work_dir + ' && ' + remote_cmd + return self.local_run(ssh_cmd + [remote_cmd]) diff --git a/test/libcxx/test/format.py b/test/libcxx/test/format.py new file mode 100644 index 000000000000..238dcdb29af7 --- /dev/null +++ b/test/libcxx/test/format.py @@ -0,0 +1,163 @@ +import errno +import os +import time + +import lit.Test # pylint: disable=import-error +import lit.TestRunner # pylint: disable=import-error +import lit.util # pylint: disable=import-error + +from libcxx.test.executor import LocalExecutor as LocalExecutor +import libcxx.util + + +class LibcxxTestFormat(object): + """ + Custom test format handler for use with the test format use by libc++. + + Tests fall into two categories: + FOO.pass.cpp - Executable test which should compile, run, and exit with + code 0. + FOO.fail.cpp - Negative test case which is expected to fail compilation. + FOO.sh.cpp - A test that uses LIT's ShTest format. + """ + + def __init__(self, cxx, use_verify_for_fail, execute_external, + executor, exec_env): + self.cxx = cxx + self.use_verify_for_fail = use_verify_for_fail + self.execute_external = execute_external + self.executor = executor + self.exec_env = dict(exec_env) + + # TODO: Move this into lit's FileBasedTest + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + source_path = testSuite.getSourcePath(path_in_suite) + for filename in os.listdir(source_path): + # Ignore dot files and excluded tests. + if filename.startswith('.') or filename in localConfig.excludes: + continue + + filepath = os.path.join(source_path, filename) + if not os.path.isdir(filepath): + if any([filename.endswith(ext) + for ext in localConfig.suffixes]): + yield lit.Test.Test(testSuite, path_in_suite + (filename,), + localConfig) + + def execute(self, test, lit_config): + while True: + try: + return self._execute(test, lit_config) + except OSError as oe: + if oe.errno != errno.ETXTBSY: + raise + time.sleep(0.1) + + def _execute(self, test, lit_config): + name = test.path_in_suite[-1] + is_sh_test = name.endswith('.sh.cpp') + is_pass_test = name.endswith('.pass.cpp') + is_fail_test = name.endswith('.fail.cpp') + + if test.config.unsupported: + return (lit.Test.UNSUPPORTED, + "A lit.local.cfg marked this unsupported") + + res = lit.TestRunner.parseIntegratedTestScript( + test, require_script=is_sh_test) + # Check if a result for the test was returned. If so return that + # result. + if isinstance(res, lit.Test.Result): + return res + if lit_config.noExecute: + return lit.Test.Result(lit.Test.PASS) + # res is not an instance of lit.test.Result. Expand res into its parts. + script, tmpBase, execDir = res + # Check that we don't have run lines on tests that don't support them. + if not is_sh_test and len(script) != 0: + lit_config.fatal('Unsupported RUN line found in test %s' % name) + + # Dispatch the test based on its suffix. + if is_sh_test: + if not isinstance(self.executor, LocalExecutor): + # We can't run ShTest tests with a executor yet. + # For now, bail on trying to run them + return lit.Test.UNSUPPORTED, 'ShTest format not yet supported' + return lit.TestRunner._runShTest(test, lit_config, + self.execute_external, script, + tmpBase, execDir) + elif is_fail_test: + return self._evaluate_fail_test(test) + elif is_pass_test: + return self._evaluate_pass_test(test, tmpBase, execDir, lit_config) + else: + # No other test type is supported + assert False + + def _clean(self, exec_path): # pylint: disable=no-self-use + libcxx.util.cleanFile(exec_path) + + def _evaluate_pass_test(self, test, tmpBase, execDir, lit_config): + source_path = test.getSourcePath() + exec_path = tmpBase + '.exe' + object_path = tmpBase + '.o' + # Create the output directory if it does not already exist. + lit.util.mkdir_p(os.path.dirname(tmpBase)) + try: + # Compile the test + cmd, out, err, rc = self.cxx.compileLinkTwoSteps( + source_path, out=exec_path, object_file=object_path, + cwd=execDir) + compile_cmd = cmd + if rc != 0: + report = libcxx.util.makeReport(cmd, out, err, rc) + report += "Compilation failed unexpectedly!" + return lit.Test.FAIL, report + # Run the test + local_cwd = os.path.dirname(source_path) + env = None + if self.exec_env: + env = self.exec_env + # TODO: Only list actually needed files in file_deps. + # Right now we just mark all of the .dat files in the same + # directory as dependencies, but it's likely less than that. We + # should add a `// FILE-DEP: foo.dat` to each test to track this. + data_files = [os.path.join(local_cwd, f) + for f in os.listdir(local_cwd) if f.endswith('.dat')] + cmd, out, err, rc = self.executor.run(exec_path, [exec_path], + local_cwd, data_files, env) + if rc != 0: + report = libcxx.util.makeReport(cmd, out, err, rc) + report = "Compiled With: %s\n%s" % (compile_cmd, report) + report += "Compiled test failed unexpectedly!" + return lit.Test.FAIL, report + return lit.Test.PASS, '' + finally: + # Note that cleanup of exec_file happens in `_clean()`. If you + # override this, cleanup is your reponsibility. + libcxx.util.cleanFile(object_path) + self._clean(exec_path) + + def _evaluate_fail_test(self, test): + source_path = test.getSourcePath() + with open(source_path, 'r') as f: + contents = f.read() + verify_tags = ['expected-note', 'expected-remark', 'expected-warning', + 'expected-error', 'expected-no-diagnostics'] + use_verify = self.use_verify_for_fail and \ + any([tag in contents for tag in verify_tags]) + extra_flags = [] + if use_verify: + extra_flags += ['-Xclang', '-verify', + '-Xclang', '-verify-ignore-unexpected=note'] + cmd, out, err, rc = self.cxx.compile(source_path, out=os.devnull, + flags=extra_flags) + expected_rc = 0 if use_verify else 1 + if rc == expected_rc: + return lit.Test.PASS, '' + else: + report = libcxx.util.makeReport(cmd, out, err, rc) + report_msg = ('Expected compilation to fail!' if not use_verify else + 'Expected compilation using verify to pass!') + return lit.Test.FAIL, report + report_msg + '\n' diff --git a/test/libcxx/test/target_info.py b/test/libcxx/test/target_info.py new file mode 100644 index 000000000000..a61737786896 --- /dev/null +++ b/test/libcxx/test/target_info.py @@ -0,0 +1,55 @@ +import locale +import platform +import sys + +class TargetInfo(object): + def platform(self): + raise NotImplementedError + + def system(self): + raise NotImplementedError + + def platform_ver(self): + raise NotImplementedError + + def platform_name(self): + raise NotImplementedError + + def supports_locale(self, loc): + raise NotImplementedError + + +class LocalTI(TargetInfo): + def platform(self): + platform_name = sys.platform.lower().strip() + # Strip the '2' from linux2. + if platform_name.startswith('linux'): + platform_name = 'linux' + return platform_name + + def system(self): + return platform.system() + + def platform_name(self): + if self.platform() == 'linux': + name, _, _ = platform.linux_distribution() + name = name.lower().strip() + if name: + return name + return None + + def platform_ver(self): + if self.platform() == 'linux': + _, ver, _ = platform.linux_distribution() + ver = ver.lower().strip() + if ver: + return ver + return None + + def supports_locale(self, loc): + try: + locale.setlocale(locale.LC_ALL, loc) + return True + except locale.Error: + return False + diff --git a/test/libcxx/test/tracing.py b/test/libcxx/test/tracing.py new file mode 100644 index 000000000000..efef158160c5 --- /dev/null +++ b/test/libcxx/test/tracing.py @@ -0,0 +1,34 @@ +import os +import inspect + + +def trace_function(function, log_calls, log_results, label=''): + def wrapper(*args, **kwargs): + kwarg_strs = ['{}={}'.format(k, v) for (k, v) in kwargs] + arg_str = ', '.join([str(a) for a in args] + kwarg_strs) + call_str = '{}({})'.format(function.func_name, arg_str) + + # Perform the call itself, logging before, after, and anything thrown. + try: + if log_calls: + print '{}: Calling {}'.format(label, call_str) + res = function(*args, **kwargs) + if log_results: + print '{}: {} -> {}'.format(label, call_str, res) + return res + except Exception as ex: + if log_results: + print '{}: {} raised {}'.format(label, call_str, type(ex)) + raise ex + + return wrapper + + +def trace_object(obj, log_calls, log_results, label=''): + for name, member in inspect.getmembers(obj): + if inspect.ismethod(member): + # Skip meta-functions, decorate everything else + if not member.func_name.startswith('__'): + setattr(obj, name, trace_function(member, log_calls, + log_results, label)) + return obj diff --git a/test/libcxx/type_traits/convert_to_integral.pass.cpp b/test/libcxx/type_traits/convert_to_integral.pass.cpp new file mode 100644 index 000000000000..b97832b5e6d7 --- /dev/null +++ b/test/libcxx/type_traits/convert_to_integral.pass.cpp @@ -0,0 +1,94 @@ + +// TODO: Make this test pass for all standards. +// XFAIL: c++98, c++03 + +#include +#include +#include +#include + +#include "user_defined_integral.hpp" + +template +struct EnumType +{ + enum type : T {E_zero, E_one}; +}; + + +template +void check_integral_types() +{ + typedef std::numeric_limits Limits; + const From max = Limits::max(); + const From min = Limits::min(); + { + auto ret = std::__convert_to_integral((From)max); + assert(ret == max); + ret = std::__convert_to_integral((From)min); + assert(ret == min); + static_assert(std::is_same::value, ""); + } + { + UserDefinedIntegral f(max); + auto ret = std::__convert_to_integral(f); + assert(ret == max); + f.value = min; + ret = std::__convert_to_integral(f); + assert(ret == min); + static_assert(std::is_same::value, ""); + } + { + typedef typename EnumType::type Enum; + Enum e(static_cast(max)); + auto ret = std::__convert_to_integral(e); + assert(ret == max); + e = static_cast(min); + ret = std::__convert_to_integral(min); + assert(ret == min); + static_assert(std::is_same::value, ""); + } +} + + +template +void check_enum_types() +{ + auto ret = std::__convert_to_integral((From)1); + assert(ret == 1); + static_assert(std::is_same::value, ""); +} + + +enum enum1 { zero = 0, one = 1 }; +enum enum2 { + value = std::numeric_limits::max() +}; + +int main() +{ + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); +#ifndef _LIBCPP_HAS_NO_INT128 + check_integral_types<__int128_t, __int128_t>(); + check_integral_types<__uint128_t, __uint128_t>(); +#endif + // TODO(ericwf): Not standard + typedef std::underlying_type::type Enum1UT; + check_enum_types(); + typedef std::underlying_type::type Enum2UT; + check_enum_types(); +} diff --git a/test/libcxx/util.py b/test/libcxx/util.py new file mode 100644 index 000000000000..28f2619d69cb --- /dev/null +++ b/test/libcxx/util.py @@ -0,0 +1,46 @@ +from contextlib import contextmanager +import os +import tempfile + + +def cleanFile(filename): + try: + os.remove(filename) + except OSError: + pass + + +@contextmanager +def guardedTempFilename(suffix='', prefix='', dir=None): + # Creates and yeilds a temporary filename within a with statement. The file + # is removed upon scope exit. + handle, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir) + os.close(handle) + yield name + cleanFile(name) + + +@contextmanager +def guardedFilename(name): + # yeilds a filename within a with statement. The file is removed upon scope + # exit. + yield name + cleanFile(name) + + +@contextmanager +def nullContext(value): + # yeilds a variable within a with statement. No action is taken upon scope + # exit. + yield value + + +def makeReport(cmd, out, err, rc): + report = "Command: %s\n" % cmd + report += "Exit Code: %d\n" % rc + if out: + report += "Standard Output:\n--\n%s--\n" % out + if err: + report += "Standard Error:\n--\n%s--\n" % err + report += '\n' + return report diff --git a/test/libcxx/utilities/memory/util.smartptr/race_condition.pass.cpp b/test/libcxx/utilities/memory/util.smartptr/race_condition.pass.cpp new file mode 100644 index 000000000000..25dd31190685 --- /dev/null +++ b/test/libcxx/utilities/memory/util.smartptr/race_condition.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: libcpp-has-no-threads +// +// +// +// class shared_ptr +// +// This test attempts to create a race condition surrounding use_count() +// with the hope that TSAN will diagnose it. + +#include +#include +#include +#include + +typedef std::shared_ptr Ptr; +typedef std::weak_ptr WeakPtr; + +std::atomic_bool Start; +std::atomic_bool KeepRunning; + +struct TestRunner { + TestRunner(Ptr xx) : x(xx) {} + void operator()() { + while (Start == false) {} + while (KeepRunning) { + // loop to prevent always checking the atomic. + for (int i=0; i < 100000; ++i) { + Ptr x2 = x; // increment shared count + WeakPtr x3 = x; // increment weak count + Ptr x4 = x3.lock(); // increment shared count via lock + WeakPtr x5 = x3; // increment weak count + } + } + } + Ptr x; +}; + +void run_test(Ptr p) { + Start = false; + KeepRunning = true; + assert(p.use_count() == 2); + TestRunner r(p); + assert(p.use_count() == 3); + std::thread t1(r); // Start the test thread. + assert(p.use_count() == 4); + Start = true; + // Run until we witness 25 use count changes via both + // shared and weak pointer methods. + WeakPtr w = p; + int shared_changes_count = 0; + int weak_changes_count = 0; + while (shared_changes_count < 25 && weak_changes_count < 25) { + // check use_count on the shared_ptr + int last = p.use_count(); + int new_val = p.use_count(); + assert(last >= 4); + assert(new_val >= 4); + if (last != new_val) ++shared_changes_count; + // Check use_count on the weak_ptr + last = w.use_count(); + new_val = w.use_count(); + assert(last >= 4); + assert(new_val >= 4); + if (last != new_val) ++weak_changes_count; + } + // kill the test thread. + KeepRunning = false; + t1.join(); + assert(p.use_count() == 3); +} + +int main() { + { + // Test with out-of-place shared_count. + Ptr p(new int(42)); + run_test(p); + assert(p.use_count() == 1); + } + { + // Test with in-place shared_count. + Ptr p = std::make_shared(42); + run_test(p); + assert(p.use_count() == 1); + } +} -- cgit v1.2.3