Index: libcxx/CMakeLists.txt =================================================================== --- libcxx/CMakeLists.txt +++ libcxx/CMakeLists.txt @@ -88,7 +88,13 @@ option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." OFF) option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON) option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON) -option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON) +set(ENABLE_EXPERIMENTAL_DEFAULT ON) +if (WIN32 AND LIBCXX_ENABLE_SHARED) + # When libc++ is built as a DLL, all headers indicate DLL linkage, while + # libc++experimental always is linked statically. + set(ENABLE_EXPERIMENTAL_DEFAULT OFF) +endif() +option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ${ENABLE_EXPERIMENTAL_DEFAULT}) set(ENABLE_FILESYSTEM_DEFAULT ON) if (WIN32 AND NOT MINGW) # Filesystem is buildable for windows, but it requires __int128 helper @@ -399,6 +405,14 @@ message(FATAL_ERROR "Only one of LIBCXX_ABI_FORCE_ITANIUM and LIBCXX_ABI_FORCE_MICROSOFT can be specified.") endif () +if (WIN32 AND LIBCXX_ENABLE_SHARED AND LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY) + message(FATAL_ERROR "LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY can't be enabled" + " when LIBCXX_ENABLE_SHARED also is enabled for Windows." + " The c++experimental library is only built as a" + " static library, while the headers signal dllimport" + " linkage.") +endif() + #=============================================================================== # Configure System #=============================================================================== Index: libcxx/docs/BuildingLibcxx.rst =================================================================== --- libcxx/docs/BuildingLibcxx.rst +++ libcxx/docs/BuildingLibcxx.rst @@ -90,7 +90,6 @@ -T "ClangCL" ^ -DLIBCXX_ENABLE_SHARED=YES ^ -DLIBCXX_ENABLE_STATIC=NO ^ - -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=NO ^ \path\to\libcxx > cmake --build . @@ -120,7 +119,6 @@ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_C_COMPILER=clang-cl ^ -DCMAKE_CXX_COMPILER=clang-cl ^ - -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=NO ^ path/to/libcxx > ninja cxx > ninja check-cxx Index: libcxx/include/functional =================================================================== --- libcxx/include/functional +++ libcxx/include/functional @@ -3184,7 +3184,7 @@ // default searcher template> -class _LIBCPP_TYPE_VIS default_searcher { +class _LIBCPP_TEMPLATE_VIS default_searcher { public: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 default_searcher(_ForwardIterator __f, _ForwardIterator __l, Index: libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp =================================================================== --- libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp +++ libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp @@ -18,8 +18,6 @@ // UNSUPPORTED: apple-clang-9 // UNSUPPORTED: gcc-5 -// XFAIL: LIBCXX-WINDOWS-FIXME - // All entities to which libc++ applies [[nodiscard]] as an extension should // be tested here and in nodiscard_extensions.fail.cpp. They should also // be listed in `UsingLibcxx.rst` in the documentation for the extension. Index: libcxx/test/libcxx/experimental/lit.local.cfg =================================================================== --- libcxx/test/libcxx/experimental/lit.local.cfg +++ libcxx/test/libcxx/experimental/lit.local.cfg @@ -1,3 +1,7 @@ # Disable all of the experimental tests if the correct feature is not available. if 'c++experimental' not in config.available_features: config.unsupported = True +# If built as a DLL on Windows, headers indicate DLL linkage, which breaks +# linking against the static-only libc++experimental. +if config.enable_shared and 'windows' in config.available_features: + config.unsupported = True Index: libcxx/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp =================================================================== --- libcxx/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp +++ libcxx/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp @@ -14,6 +14,8 @@ // T* polymorphic_allocator::deallocate(T*, size_t size) +// XFAIL: LIBCXX-WINDOWS-FIXME + int AssertCount = 0; #define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++) Index: libcxx/test/std/experimental/lit.local.cfg =================================================================== --- libcxx/test/std/experimental/lit.local.cfg +++ libcxx/test/std/experimental/lit.local.cfg @@ -1,3 +1,7 @@ # Disable all of the experimental tests if the correct feature is not available. if 'c++experimental' not in config.available_features: config.unsupported = True +# If built as a DLL on Windows, headers indicate DLL linkage, which breaks +# linking against the static-only libc++experimental. +if config.enable_shared and 'windows' in config.available_features: + config.unsupported = True Index: libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp @@ -11,8 +11,6 @@ // These tests require locale for non-char paths // UNSUPPORTED: libcpp-has-no-localization -// XFAIL: LIBCXX-WINDOWS-FIXME - // // class path @@ -197,6 +195,9 @@ // required. // On Windows, the append method is more complex and uses intermediate // path objects, which causes extra allocations. + // In DLL builds on Windows, the overridden operator new won't pick up + // allocations done within the DLL, so the RequireAllocationGuard below + // won't necessarily see allocations in the cases where they're expected. #ifdef _WIN32 bool DisableAllocations = false; #else @@ -208,6 +209,7 @@ { RequireAllocationGuard g; // requires 1 or more allocations occur by default if (DisableAllocations) g.requireExactly(0); + else TEST_ONLY_WIN32(g.requireAtLeast(0)); LHS /= RHS; } assert(PathEq(LHS, E)); @@ -219,6 +221,7 @@ { RequireAllocationGuard g; if (DisableAllocations) g.requireExactly(0); + else TEST_ONLY_WIN32(g.requireAtLeast(0)); LHS.append(RHS, REnd); } assert(PathEq(LHS, E)); Index: libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp @@ -8,8 +8,6 @@ // UNSUPPORTED: c++03 -// XFAIL: LIBCXX-WINDOWS-FIXME - // // class path @@ -30,7 +28,9 @@ assert(globalMemCounter.checkOutstandingNewEq(0)); const std::string s("we really really really really really really really " "really really long string so that we allocate"); - assert(globalMemCounter.checkOutstandingNewEq(1)); + // On windows, the operator new from count_new.h can't override the default + // operator for calls within the libc++ DLL. + TEST_NOT_WIN32(assert(globalMemCounter.checkOutstandingNewEq(1))); const fs::path::string_type ps(s.begin(), s.end()); path p(s); { Index: libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp @@ -11,8 +11,6 @@ // These tests require locale for non-char paths // UNSUPPORTED: libcpp-has-no-localization -// XFAIL: LIBCXX-WINDOWS-FIXME - // // class path @@ -142,6 +140,10 @@ // code_cvt conversions. // For the path native type, no allocations will be performed because no // conversion is required. + + // In DLL builds on Windows, the overridden operator new won't pick up + // allocations done within the DLL, so the RequireAllocationGuard below + // won't necessarily see allocations in the cases where they're expected. bool DisableAllocations = std::is_same::value; { path LHS(L); PathReserve(LHS, ReserveSize); @@ -149,6 +151,7 @@ { RequireAllocationGuard g; // requires 1 or more allocations occur by default if (DisableAllocations) g.requireExactly(0); + else TEST_ONLY_WIN32(g.requireAtLeast(0)); LHS += RHS; } assert(LHS == E); @@ -160,6 +163,7 @@ { RequireAllocationGuard g; if (DisableAllocations) g.requireExactly(0); + else TEST_ONLY_WIN32(g.requireAtLeast(0)); LHS.concat(RHS, REnd); } assert(LHS == E); Index: libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp @@ -8,8 +8,6 @@ // UNSUPPORTED: c++03 -// XFAIL: LIBCXX-WINDOWS-FIXME - // // class path @@ -30,7 +28,9 @@ assert(globalMemCounter.checkOutstandingNewEq(0)); const std::string s("we really really really really really really really " "really really long string so that we allocate"); - assert(globalMemCounter.checkOutstandingNewEq(1)); + // On windows, the operator new from count_new.h can't override the default + // operator for calls within the libc++ DLL. + TEST_NOT_WIN32(assert(globalMemCounter.checkOutstandingNewEq(1))); const fs::path::string_type ps(s.begin(), s.end()); path p(s); { Index: libcxx/test/std/localization/locale.categories/category.collate/locale.collate.byname/hash.pass.cpp =================================================================== --- libcxx/test/std/localization/locale.categories/category.collate/locale.collate.byname/hash.pass.cpp +++ libcxx/test/std/localization/locale.categories/category.collate/locale.collate.byname/hash.pass.cpp @@ -8,7 +8,8 @@ // REQUIRES: locale.en_US.UTF-8 -// XFAIL: LIBCXX-WINDOWS-FIXME +// https://bugs.llvm.org/show_bug.cgi?id=41018 +// XFAIL: windows-dll // Index: libcxx/test/std/localization/locale.categories/category.collate/locale.collate/locale.collate.members/compare.pass.cpp =================================================================== --- libcxx/test/std/localization/locale.categories/category.collate/locale.collate/locale.collate.members/compare.pass.cpp +++ libcxx/test/std/localization/locale.categories/category.collate/locale.collate/locale.collate.members/compare.pass.cpp @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +// https://bugs.llvm.org/show_bug.cgi?id=41018 +// XFAIL: windows-dll + // // template class collate; @@ -13,8 +16,6 @@ // int compare(const charT* low1, const charT* high1, // const charT* low2, const charT* high2) const; -// XFAIL: LIBCXX-WINDOWS-FIXME - #include #include Index: libcxx/test/std/localization/locale.categories/category.collate/locale.collate/locale.collate.members/hash.pass.cpp =================================================================== --- libcxx/test/std/localization/locale.categories/category.collate/locale.collate/locale.collate.members/hash.pass.cpp +++ libcxx/test/std/localization/locale.categories/category.collate/locale.collate/locale.collate.members/hash.pass.cpp @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +// https://bugs.llvm.org/show_bug.cgi?id=41018 +// XFAIL: windows-dll + // // template class collate; @@ -14,8 +17,6 @@ // This test is not portable -// XFAIL: LIBCXX-WINDOWS-FIXME - #include #include #include Index: libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp =================================================================== --- libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp +++ libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp @@ -12,8 +12,6 @@ // ~ctype(); -// XFAIL: LIBCXX-WINDOWS-FIXME - #include #include @@ -39,7 +37,7 @@ new std::ctype(new std::ctype::mask[256], true)); assert(globalMemCounter.checkDeleteArrayCalledEq(0)); } - assert(globalMemCounter.checkDeleteArrayCalledEq(1)); + TEST_NOT_WIN32(assert(globalMemCounter.checkDeleteArrayCalledEq(1))); return 0; } Index: libcxx/test/std/localization/locales/locale/locale.operators/compare.pass.cpp =================================================================== --- libcxx/test/std/localization/locales/locale/locale.operators/compare.pass.cpp +++ libcxx/test/std/localization/locales/locale/locale.operators/compare.pass.cpp @@ -6,7 +6,8 @@ // //===----------------------------------------------------------------------===// -// XFAIL: LIBCXX-WINDOWS-FIXME +// https://bugs.llvm.org/show_bug.cgi?id=41018 +// XFAIL: windows-dll // Index: libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp =================================================================== --- libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp +++ libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp @@ -8,7 +8,8 @@ // // UNSUPPORTED: libcpp-has-no-threads -// XFAIL: LIBCXX-WINDOWS-FIXME +// FIXME: Unclear why this fails in DLL mode. +// XFAIL: windows-dll // Index: libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pass.cpp =================================================================== --- libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pass.cpp +++ libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pass.cpp @@ -8,7 +8,9 @@ // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: LIBCXX-WINDOWS-FIXME +// FIXME: Not known why this fails in DLL mode on the CI runner, as it +// works in local testing. +// XFAIL: windows-dll // Index: libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pred.pass.cpp =================================================================== --- libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pred.pass.cpp +++ libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pred.pass.cpp @@ -10,7 +10,9 @@ // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: LIBCXX-WINDOWS-FIXME +// FIXME: Not known why this fails in DLL mode on the CI runner, as it +// works in local testing. +// XFAIL: windows-dll // default searcher // template> Index: libcxx/test/support/test_macros.h =================================================================== --- libcxx/test/support/test_macros.h +++ libcxx/test/support/test_macros.h @@ -374,8 +374,10 @@ #ifdef _WIN32 #define TEST_NOT_WIN32(...) ((void)0) +#define TEST_ONLY_WIN32(...) __VA_ARGS__ #else #define TEST_NOT_WIN32(...) __VA_ARGS__ +#define TEST_ONLY_WIN32(...) ((void)0) #endif #if defined(__GNUC__) Index: libcxx/utils/ci/buildkite-pipeline.yml =================================================================== --- libcxx/utils/ci/buildkite-pipeline.yml +++ libcxx/utils/ci/buildkite-pipeline.yml @@ -299,10 +299,23 @@ - exit_status: -1 # Agent was lost limit: 2 - - label: "Windows" + - label: "Windows (DLL)" # TODO: The CI runner doesn't have bash in the path currently. Once it # has that, remove the absolute path and just call 'bash' here. - command: "\"\\Program Files\\Git\\usr\\bin\\bash\" libcxx/utils/ci/run-buildbot generic-win" + command: "\"\\Program Files\\Git\\usr\\bin\\bash\" libcxx/utils/ci/run-buildbot generic-win-dll" + artifact_paths: + - "**/test-results.xml" + agents: + queue: "windows" + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + + - label: "Windows (Static)" + # TODO: The CI runner doesn't have bash in the path currently. Once it + # has that, remove the absolute path and just call 'bash' here. + command: "\"\\Program Files\\Git\\usr\\bin\\bash\" libcxx/utils/ci/run-buildbot generic-win-static" artifact_paths: - "**/test-results.xml" agents: Index: libcxx/utils/ci/run-buildbot =================================================================== --- libcxx/utils/ci/run-buildbot +++ libcxx/utils/ci/run-buildbot @@ -455,7 +455,7 @@ generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Armv7Thumb-noexceptions.cmake" check-cxx-cxxabi ;; -generic-win) +generic-win*) clean # TODO: The CI runner doesn't have bash in the path currently, and it's # needed for running tests. Once it's available out of the box, remove this. @@ -475,12 +475,10 @@ # the "clang-cl" driver for compiling). When the CI runner runs # Clang 12, the "-loldnames" option can be dropped. - # TODO: Currently, building with the experimental library breaks running - # tests (the test linking look for the c++experimental library with the - # wrong name, and the statically linked c++experimental can't be linked - # correctly when libc++ visibility attributes indicate dllimport linkage - # anyway), thus just disable the experimental library. Remove this - # setting when cmake and the test driver does the right thing automatically. + CMAKE_FLAGS="" + if [ "${BUILDER}" = "generic-win-static" ]; then + CMAKE_FLAGS="$CMAKE_FLAGS -DLIBCXX_ENABLE_SHARED=NO" + fi echo "--- Generating CMake" cmake -S "${MONOREPO_ROOT}/libcxx" \ @@ -490,11 +488,11 @@ -DCMAKE_C_COMPILER=clang-cl \ -DCMAKE_CXX_COMPILER=clang-cl \ -DLLVM_LIT_ARGS="-sv --show-unsupported --xunit-xml-output test-results.xml" \ - -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=NO \ -DLIBCXX_ENABLE_FILESYSTEM=YES \ -DCMAKE_CXX_FLAGS="-D_LIBCPP_HAS_NO_INT128" \ -DLIBCXX_TEST_COMPILER_FLAGS="-D_LIBCPP_HAS_NO_INT128" \ - -DLIBCXX_TEST_LINKER_FLAGS="-loldnames" + -DLIBCXX_TEST_LINKER_FLAGS="-loldnames" \ + ${CMAKE_FLAGS} echo "+++ Running the libc++ tests" ${NINJA} -vC "${BUILD_DIR}" check-cxx ;; Index: libcxx/utils/libcxx/test/features.py =================================================================== --- libcxx/utils/libcxx/test/features.py +++ libcxx/utils/libcxx/test/features.py @@ -14,6 +14,7 @@ _isClang = lambda cfg: '__clang__' in compilerMacros(cfg) and '__apple_build_version__' not in compilerMacros(cfg) _isAppleClang = lambda cfg: '__apple_build_version__' in compilerMacros(cfg) _isGCC = lambda cfg: '__GNUC__' in compilerMacros(cfg) and '__clang__' not in compilerMacros(cfg) +_isMSVC = lambda cfg: '_MSC_VER' in compilerMacros(cfg) DEFAULT_FEATURES = [ Feature(name='fcoroutines-ts', @@ -81,6 +82,8 @@ Feature(name=lambda cfg: 'gcc-{__GNUC__}'.format(**compilerMacros(cfg)), when=_isGCC), Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}'.format(**compilerMacros(cfg)), when=_isGCC), Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}'.format(**compilerMacros(cfg)), when=_isGCC), + + Feature(name='msvc', when=_isMSVC), ] # Deduce and add the test features that that are implied by the #defines in @@ -147,6 +150,7 @@ DEFAULT_FEATURES += [ Feature(name='darwin', when=lambda cfg: '__APPLE__' in compilerMacros(cfg)), Feature(name='windows', when=lambda cfg: '_WIN32' in compilerMacros(cfg)), + Feature(name='windows-dll', when=lambda cfg: '_WIN32' in compilerMacros(cfg) and cfg.enable_shared), Feature(name='linux', when=lambda cfg: '__linux__' in compilerMacros(cfg)), Feature(name='netbsd', when=lambda cfg: '__NetBSD__' in compilerMacros(cfg)), Feature(name='freebsd', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg)) Index: libcxx/utils/libcxx/test/params.py =================================================================== --- libcxx/utils/libcxx/test/params.py +++ libcxx/utils/libcxx/test/params.py @@ -7,6 +7,7 @@ #===----------------------------------------------------------------------===## from libcxx.test.dsl import * +from libcxx.test.features import _isMSVC _allStandards = ['c++03', 'c++11', 'c++14', 'c++17', 'c++2a', 'c++2b'] _warningFlags = [ @@ -91,7 +92,12 @@ help="Whether to enable tests for experimental C++ libraries (typically Library Fundamentals TSes).", actions=lambda experimental: [] if not experimental else [ AddFeature('c++experimental'), - PrependLinkFlag('-lc++experimental') + # When linking in MSVC mode via the Clang driver, a -l + # maps to .lib, so we need to use -llibc++experimental here + # to make it link against the static libc++experimental.lib. + # We can't check for the feature 'msvc' in available_features + # as those features are added after processing parameters. + PrependLinkFlag(lambda config: '-llibc++experimental' if _isMSVC(config) else '-lc++experimental') ]), Parameter(name='long_tests', choices=[True, False], type=bool, default=True,