diff --git a/libcxx/docs/Contributing.rst b/libcxx/docs/Contributing.rst --- a/libcxx/docs/Contributing.rst +++ b/libcxx/docs/Contributing.rst @@ -23,18 +23,19 @@ 2. Update the ``include/__libcpp_version`` file 3. Update the version number in ``docs/conf.py`` +Modifying feature test macros +============================= + +When adding or updating feature test macros, you should update the corresponding tests. +To do that, modify ``feature_test_macros`` table in the script ``utils/generate_feature_test_macro_components.py``, run it, and commit updated files. + Adding a new header TODO ======================== When adding a new header to libc++: 1. Add a test under ``test/libcxx`` that the new header defines ``_LIBCPP_VERSION``. See ``test/libcxx/algorithms/version.pass.cpp`` for an example. -2. Update the following test files to include the new header: - - * ``test/libcxx/double_include.sh.cpp`` - * ``test/libcxx/min_max_macros.compile.pass.cpp`` - * ``test/libcxx/no_assert_include.compile.pass.cpp`` - +2. Run ``python utils/generate_header_tests.py``, verify and commit the modifications. 3. Create a submodule in ``include/module.modulemap`` for the new header. 4. Update the ``include/CMakeLists.txt`` file to include the new header. diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp --- a/libcxx/test/libcxx/double_include.sh.cpp +++ b/libcxx/test/libcxx/double_include.sh.cpp @@ -19,20 +19,29 @@ // when included. // UNSUPPORTED: gcc-5 && c++17 +// clang-format off + // Prevent from generating deprecated warnings for this test. #if defined(__DEPRECATED) -#undef __DEPRECATED +# undef __DEPRECATED #endif +//////////////////////////////////////////////////////////////////////////////// +// BEGIN-GENERATED-HEADERS +//////////////////////////////////////////////////////////////////////////////// + +// WARNING: This test was generated by generate_header_tests.py +// and should not be edited manually. + // Top level headers #include #include #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include @@ -47,7 +56,13 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include @@ -75,43 +90,73 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include @@ -119,13 +164,19 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include @@ -141,55 +192,42 @@ #include #include -#ifndef _LIBCPP_HAS_NO_LOCALIZATION -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# if __cplusplus >= 201103L -# include -# endif -#endif - // experimental headers #if __cplusplus >= 201103L -#include -#if defined(__cpp_coroutines) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +# include +# if defined(__cpp_coroutines) +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include #endif // __cplusplus >= 201103L // extended headers #include #include +//////////////////////////////////////////////////////////////////////////////// +// END-GENERATED-HEADERS +//////////////////////////////////////////////////////////////////////////////// + #if defined(WITH_MAIN) int main(int, char**) { return 0; } #endif diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp --- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp @@ -13,15 +13,24 @@ // GCC 5 has incomplete support for C++17, so some headers fail when included. // UNSUPPORTED: gcc-5 && c++17 +// clang-format off + // Prevent from generating deprecated warnings for this test. #if defined(__DEPRECATED) -#undef __DEPRECATED +# undef __DEPRECATED #endif #define TEST_MACROS() static_assert(min() == true && max() == true, "") #define min() true #define max() true +//////////////////////////////////////////////////////////////////////////////// +// BEGIN-GENERATED-HEADERS +//////////////////////////////////////////////////////////////////////////////// + +// WARNING: This test was generated by generate_header_tests.py +// and should not be edited manually. + // Top level headers #include TEST_MACROS(); @@ -30,11 +39,11 @@ #include TEST_MACROS(); #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include TEST_MACROS(); #endif #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include TEST_MACROS(); #endif #include @@ -63,8 +72,16 @@ TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #include @@ -119,22 +136,42 @@ TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include TEST_MACROS(); #endif #include TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include TEST_MACROS(); #endif #include @@ -143,6 +180,14 @@ TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #include @@ -150,7 +195,7 @@ #include TEST_MACROS(); #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include TEST_MACROS(); #endif #include @@ -161,16 +206,24 @@ TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #include TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include TEST_MACROS(); #endif #include @@ -178,11 +231,15 @@ #include TEST_MACROS(); #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include TEST_MACROS(); #endif #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #include @@ -197,18 +254,26 @@ TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #include TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +TEST_MACROS(); +#endif #include TEST_MACROS(); #include TEST_MACROS(); #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include TEST_MACROS(); #endif #include @@ -238,82 +303,51 @@ #include TEST_MACROS(); -#ifndef _LIBCPP_HAS_NO_LOCALIZATION -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# include - TEST_MACROS(); -# if __cplusplus >= 201103L -# include - TEST_MACROS(); -# endif -#endif - // experimental headers #if __cplusplus >= 201103L -#include +# include TEST_MACROS(); -#if defined(__cpp_coroutines) -#include +# if defined(__cpp_coroutines) +# include TEST_MACROS(); -#endif -#include +# endif +# include +TEST_MACROS(); +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include TEST_MACROS(); -#include +# endif +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); -#include +# include TEST_MACROS(); #endif // __cplusplus >= 201103L @@ -322,3 +356,7 @@ TEST_MACROS(); #include TEST_MACROS(); + +//////////////////////////////////////////////////////////////////////////////// +// END-GENERATED-HEADERS +//////////////////////////////////////////////////////////////////////////////// diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp --- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp +++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp @@ -13,20 +13,29 @@ // GCC 5 has incomplete support for C++17, so some headers fail when included. // UNSUPPORTED: gcc-5 && c++17 +// clang-format off + // Prevent from generating deprecated warnings for this test. #if defined(__DEPRECATED) -#undef __DEPRECATED +# undef __DEPRECATED #endif +//////////////////////////////////////////////////////////////////////////////// +// BEGIN-GENERATED-HEADERS +//////////////////////////////////////////////////////////////////////////////// + +// WARNING: This test was generated by generate_header_tests.py +// and should not be edited manually. + // Top level headers #include #include #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include @@ -40,7 +49,13 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include @@ -68,43 +83,73 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include @@ -112,13 +157,19 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif #include #include #ifndef _LIBCPP_HAS_NO_THREADS -#include +# include #endif #include #include @@ -134,55 +185,42 @@ #include #include -#ifndef _LIBCPP_HAS_NO_LOCALIZATION -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# if __cplusplus >= 201103L -# include -# endif -#endif - // experimental headers #if __cplusplus >= 201103L -#include -#if defined(__cpp_coroutines) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +# include +# if defined(__cpp_coroutines) +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include #endif // __cplusplus >= 201103L // extended headers #include #include +//////////////////////////////////////////////////////////////////////////////// +// END-GENERATED-HEADERS +//////////////////////////////////////////////////////////////////////////////// + #ifdef assert #error "Do not include cassert or assert.h in standard header files" #endif diff --git a/libcxx/utils/generate_header_tests.py b/libcxx/utils/generate_header_tests.py new file mode 100644 --- /dev/null +++ b/libcxx/utils/generate_header_tests.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python + +import glob +import os +import posixpath +import re + + +def get_libcxx_paths(): + utils_path = os.path.dirname(os.path.abspath(__file__)) + script_name = os.path.basename(__file__) + assert os.path.exists(utils_path) + src_root = os.path.dirname(utils_path) + include_path = os.path.join(src_root, 'include') + assert os.path.exists(include_path) + libcxx_test_path = os.path.join(src_root, 'test', 'libcxx') + assert os.path.exists(libcxx_test_path) + return script_name, src_root, include_path, libcxx_test_path + + +script_name, source_root, include_path, libcxx_test_path = get_libcxx_paths() + +header_markup = { + "atomic": ["ifndef _LIBCPP_HAS_NO_THREADS"], + "barrier": ["ifndef _LIBCPP_HAS_NO_THREADS"], + "future": ["ifndef _LIBCPP_HAS_NO_THREADS"], + "latch": ["ifndef _LIBCPP_HAS_NO_THREADS"], + "mutex": ["ifndef _LIBCPP_HAS_NO_THREADS"], + "shared_mutex": ["ifndef _LIBCPP_HAS_NO_THREADS"], + "semaphore": ["ifndef _LIBCPP_HAS_NO_THREADS"], + "thread": ["ifndef _LIBCPP_HAS_NO_THREADS"], + + "clocale": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "codecvt": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "fstream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "iomanip": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "ios": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "iostream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "istream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "locale": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "locale.h": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "ostream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "regex": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "sstream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "streambuf": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + "strstream": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], + + "experimental/coroutine": ["if defined(__cpp_coroutines)"], + "experimental/regex": ["ifndef _LIBCPP_HAS_NO_LOCALIZATION"], +} + +allowed_extensions = ['', '.h'] +indent_width = 4 + + +begin_pattern = """\ +//////////////////////////////////////////////////////////////////////////////// +// BEGIN-GENERATED-HEADERS +//////////////////////////////////////////////////////////////////////////////// +""" + +warning_note = """\ +// WARNING: This test was generated by {script_name} +// and should not be edited manually. + +""".format(script_name=script_name) + +end_pattern = """\ +//////////////////////////////////////////////////////////////////////////////// +// END-GENERATED-HEADERS +//////////////////////////////////////////////////////////////////////////////// +""" + +generated_part_pattern = re.compile(re.escape(begin_pattern) + ".*" + re.escape(end_pattern), + re.MULTILINE | re.DOTALL) + +headers_template = """\ +// Top level headers +{top_level_headers} + +// experimental headers +#if __cplusplus >= 201103L +{experimental_headers} +#endif // __cplusplus >= 201103L + +// extended headers +{extended_headers} +""" + + +def should_keep_header(p, exclusions=None): + if os.path.isdir(p): + return False + + if exclusions: + relpath = os.path.relpath(p, include_path) + relpath = posixpath.join(*os.path.split(relpath)) + if relpath in exclusions: + print('Excluded file:', relpath) + return False + + return os.path.splitext(p)[1] in allowed_extensions + + +def produce_include(relpath, indent_level, post_include=None): + relpath = posixpath.join(*os.path.split(relpath)) + template = "{preambule}#{indentation}include <{include}>{post_include}{postambule}" + + base_indentation = ' '*(indent_width * indent_level) + next_indentation = base_indentation + ' '*(indent_width) + post_include = "\n{}".format(post_include) if post_include else '' + + markup = header_markup.get(relpath, None) + if markup: + preambule = '#{indentation}{directive}\n'.format( + directive=markup[0], + indentation=base_indentation, + ) + postambule = '\n#{indentation}endif'.format( + indentation=base_indentation, + ) + indentation = next_indentation + else: + preambule = '' + postambule = '' + indentation = base_indentation + + return template.format( + include=relpath, + post_include=post_include, + preambule=preambule, + postambule=postambule, + indentation=indentation, + ) + + +def produce_headers(path_parts, indent_level, post_include=None, exclusions=None): + pattern = os.path.join(*path_parts, '[a-z]*') + + include_headers = glob.glob(pattern, recursive=False) + + include_headers = [ + produce_include(os.path.relpath(p, include_path), + indent_level, post_include=post_include) + for p in include_headers + if should_keep_header(p, exclusions)] + + return '\n'.join(include_headers) + + +def produce_top_level_headers(post_include=None, exclusions=None): + return produce_headers([include_path], 0, post_include=post_include, exclusions=exclusions) + + +def produce_experimental_headers(post_include=None, exclusions=None): + return produce_headers([include_path, 'experimental'], 1, post_include=post_include, exclusions=exclusions) + + +def produce_extended_headers(post_include=None, exclusions=None): + return produce_headers([include_path, 'ext'], 0, post_include=post_include, exclusions=exclusions) + + +def replace_generated_headers(test_path, test_str): + with open(test_path, 'r') as f: + content = f.read() + + content = generated_part_pattern.sub(begin_pattern + '\n' + warning_note + test_str + + '\n' + end_pattern, content) + + with open(test_path, 'w') as f: + f.write(content) + + +def produce_test(test_filename, exclusions=None, post_include=None): + test_str = headers_template.format( + top_level_headers=produce_top_level_headers( + post_include=post_include, + exclusions=exclusions, + ), + experimental_headers=produce_experimental_headers( + post_include=post_include, + ), + extended_headers=produce_extended_headers( + post_include=post_include, + ), + ) + + replace_generated_headers(os.path.join( + libcxx_test_path, test_filename), test_str) + + +def main(): + produce_test('double_include.sh.cpp') + produce_test('min_max_macros.compile.pass.cpp', + post_include='TEST_MACROS();') + produce_test('no_assert_include.compile.pass.cpp', + exclusions=['cassert']) + + +if __name__ == '__main__': + main()