Skip to content

Commit

Permalink
Add extern "C++" as a temporary workaround for #include/import
Browse files Browse the repository at this point in the history
…coexistence (#4154)
  • Loading branch information
StephanTLavavej authored Nov 10, 2023
1 parent d3873a5 commit 46843b3
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 18 deletions.
2 changes: 2 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ SpaceBeforeParensOptions:
# NOTE: _STD_BEGIN, _STD_END, etc. aren't macros for complete statements, but telling
# clang-format that they are produces the behavior that we want (with no block indentation).
StatementMacros:
- _EXTERN_CXX_WORKAROUND
- _END_EXTERN_CXX_WORKAROUND
- _STD_BEGIN
- _STD_END
- _STDEXT_BEGIN
Expand Down
4 changes: 4 additions & 0 deletions stl/inc/cmath
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ _STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_EXTERN_CXX_WORKAROUND
_NODISCARD _Check_return_ inline float acos(_In_ float _Xx) noexcept /* strengthened */ {
return _CSTD acosf(_Xx);
}
Expand Down Expand Up @@ -552,6 +553,7 @@ _NODISCARD _Check_return_ inline long double trunc(_In_ long double _Xx) noexcep
return _CSTD truncl(_Xx);
#endif // ^^^ intrinsics unavailable ^^^
}
_END_EXTERN_CXX_WORKAROUND

_STD_BEGIN
template <class _Ty1, class _Ty2>
Expand All @@ -560,6 +562,7 @@ using _Common_float_type_t = conditional_t<is_same_v<_Ty1, long double> || is_sa
double>>; // find type for two-argument math function
_STD_END

_EXTERN_CXX_WORKAROUND
template <class _Ty, _STD enable_if_t<_STD is_integral_v<_Ty>, int> = 0>
double frexp(_Ty _Value, _Out_ int* const _Exp) noexcept /* strengthened */ {
return _CSTD frexp(static_cast<double>(_Value), _Exp);
Expand Down Expand Up @@ -709,6 +712,7 @@ _GENERIC_MATH2(fmin)
#undef _GENERIC_MATH2
#undef _GENERIC_MATH2I
#undef _HAS_CMATH_INTRINSICS
_END_EXTERN_CXX_WORKAROUND

_STD_BEGIN
_EXPORT_STD using _CSTD abs;
Expand Down
2 changes: 2 additions & 0 deletions stl/inc/cstddef
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ _NODISCARD _MSVC_INTRINSIC constexpr _IntType to_integer(const byte _Arg) noexce

_STD_END

_EXTERN_CXX_WORKAROUND
using _STD max_align_t; // intentional, for historical reasons
_END_EXTERN_CXX_WORKAROUND

// TRANSITION, non-_Ugly attribute tokens
#pragma pop_macro("intrinsic")
Expand Down
2 changes: 2 additions & 0 deletions stl/inc/cstdlib
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ _STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_EXTERN_CXX_WORKAROUND
// <stdlib.h> has abs(long) and abs(long long)
_NODISCARD _Check_return_ inline double abs(_In_ double _Xx) noexcept /* strengthened */ {
return _CSTD fabs(_Xx);
Expand All @@ -30,6 +31,7 @@ _NODISCARD _Check_return_ inline float abs(_In_ float _Xx) noexcept /* strengthe
_NODISCARD _Check_return_ inline long double abs(_In_ long double _Xx) noexcept /* strengthened */ {
return _CSTD fabsl(_Xx);
}
_END_EXTERN_CXX_WORKAROUND

_STD_BEGIN
_EXPORT_STD using _CSTD size_t;
Expand Down
16 changes: 8 additions & 8 deletions stl/inc/ctime
Original file line number Diff line number Diff line change
Expand Up @@ -29,44 +29,44 @@ _EXPORT_STD using _CSTD strftime;
_EXPORT_STD using _CSTD timespec;
#endif // _HAS_CXX17

#ifdef _BUILD_STD_MODULE // TRANSITION, OS-33790456
#ifdef _BUILD_STD_MODULE // TRANSITION, OS-33790456; `template <int = 0>` avoids ambiguity
_STL_DISABLE_DEPRECATED_WARNING

_EXPORT_STD
_EXPORT_STD template <int = 0>
_Check_return_ _CRT_INSECURE_DEPRECATE(ctime_s) inline char* __CRTDECL ctime(_In_ const time_t* const _Time) noexcept
/* strengthened */ {
return _CSTD _ctime64(_Time);
}

_EXPORT_STD
_EXPORT_STD template <int = 0>
_Check_return_ inline double __CRTDECL difftime(_In_ const time_t _Time1, _In_ const time_t _Time2) noexcept
/* strengthened */ {
return _CSTD _difftime64(_Time1, _Time2);
}

_EXPORT_STD
_EXPORT_STD template <int = 0>
_Check_return_ _CRT_INSECURE_DEPRECATE(gmtime_s) inline tm* __CRTDECL gmtime(_In_ const time_t* const _Time) noexcept
/* strengthened */ {
return _CSTD _gmtime64(_Time);
}

_EXPORT_STD
_EXPORT_STD template <int = 0>
_CRT_INSECURE_DEPRECATE(localtime_s)
inline tm* __CRTDECL localtime(_In_ const time_t* const _Time) noexcept /* strengthened */ {
return _CSTD _localtime64(_Time);
}

_EXPORT_STD
_EXPORT_STD template <int = 0>
_Check_return_opt_ inline time_t __CRTDECL mktime(_Inout_ tm* const _Tm) noexcept /* strengthened */ {
return _CSTD _mktime64(_Tm);
}

_EXPORT_STD
_EXPORT_STD template <int = 0>
inline time_t __CRTDECL time(_Out_opt_ time_t* const _Time) noexcept /* strengthened */ {
return _CSTD _time64(_Time);
}

_EXPORT_STD
_EXPORT_STD template <int = 0>
_Check_return_ inline int __CRTDECL timespec_get(_Out_ timespec* const _Ts, _In_ const int _Base) noexcept
/* strengthened */ {
return _CSTD _timespec64_get(reinterpret_cast<_timespec64*>(_Ts), _Base);
Expand Down
2 changes: 2 additions & 0 deletions stl/inc/cwchar
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ _STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_EXTERN_CXX_WORKAROUND
using _Mbstatet = mbstate_t;
_END_EXTERN_CXX_WORKAROUND

_STD_BEGIN
#pragma warning(push)
Expand Down
10 changes: 10 additions & 0 deletions stl/inc/xfilesystem_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ enum class __std_fs_file_attr : unsigned long {
};
} // extern "C"

_EXTERN_CXX_WORKAROUND
_BITMASK_OPS(_EMPTY_ARGUMENT, __std_fs_file_attr)
_END_EXTERN_CXX_WORKAROUND

extern "C" {
enum class __std_fs_reparse_tag : unsigned long {
Expand Down Expand Up @@ -123,7 +125,9 @@ enum class __std_fs_stats_flags : unsigned long {
};
} // extern "C"

_EXTERN_CXX_WORKAROUND
_BITMASK_OPS(_EMPTY_ARGUMENT, __std_fs_stats_flags)
_END_EXTERN_CXX_WORKAROUND

extern "C" {
struct __std_fs_stats {
Expand Down Expand Up @@ -199,7 +203,9 @@ enum class __std_access_rights : unsigned long {
};
} // extern "C"

_EXTERN_CXX_WORKAROUND
_BITMASK_OPS(_EMPTY_ARGUMENT, __std_access_rights)
_END_EXTERN_CXX_WORKAROUND

extern "C" {
enum class __std_fs_file_flags : unsigned long {
Expand All @@ -209,7 +215,9 @@ enum class __std_fs_file_flags : unsigned long {
};
} // extern "C"

_EXTERN_CXX_WORKAROUND
_BITMASK_OPS(_EMPTY_ARGUMENT, __std_fs_file_flags)
_END_EXTERN_CXX_WORKAROUND

extern "C" {
enum class __std_fs_file_handle : intptr_t { _Invalid = -1 };
Expand All @@ -236,7 +244,9 @@ enum class __std_fs_copy_options {
};
} // extern "C"

_EXTERN_CXX_WORKAROUND
_BITMASK_OPS(_EMPTY_ARGUMENT, __std_fs_copy_options)
_END_EXTERN_CXX_WORKAROUND

extern "C" {
_NODISCARD __std_ulong_and_error __stdcall __std_fs_get_full_path_name(_In_z_ const wchar_t* _Source,
Expand Down
49 changes: 41 additions & 8 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1941,16 +1941,49 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error.
#define _STRINGIZE(x) _STRINGIZEX(x)
#define _EMPTY_ARGUMENT // for empty macro argument

#define _STD_BEGIN namespace std {
#define _STD_END }
#define _STD ::std::
#define _CHRONO ::std::chrono::
#define _RANGES ::std::ranges::
// extern "C++" attaches declarations to the global module, see N4964 [module.unit]/7.2.
// It has no effect in C++14/17.

// In the STL's headers (which might be used to build the named module std), we unconditionally
// and directly mark declarations of our separately compiled machinery as extern "C++", allowing
// the named module to work with the separately compiled code (which is always built classically).

// TRANSITION: _USE_EXTERN_CXX_EVERYWHERE_FOR_STL controls whether we also wrap the STL's
// header-only code in this linkage-specification, as a temporary workaround to allow
// the named module to coexist with classic includes in the same translation unit.

#ifndef _USE_EXTERN_CXX_EVERYWHERE_FOR_STL
#define _USE_EXTERN_CXX_EVERYWHERE_FOR_STL _HAS_CXX20
#endif // ^^^ !defined(_USE_EXTERN_CXX_EVERYWHERE_FOR_STL) ^^^

#if _USE_EXTERN_CXX_EVERYWHERE_FOR_STL
#define _EXTERN_CXX_WORKAROUND extern "C++" {
#define _END_EXTERN_CXX_WORKAROUND }
#else // ^^^ _USE_EXTERN_CXX_EVERYWHERE_FOR_STL / !_USE_EXTERN_CXX_EVERYWHERE_FOR_STL vvv
#define _EXTERN_CXX_WORKAROUND
#define _END_EXTERN_CXX_WORKAROUND
#endif // ^^^ !_USE_EXTERN_CXX_EVERYWHERE_FOR_STL ^^^

#define _STD_BEGIN \
_EXTERN_CXX_WORKAROUND \
namespace std {
#define _STD_END \
} \
_END_EXTERN_CXX_WORKAROUND

#define _STD ::std::
#define _CHRONO ::std::chrono::
#define _RANGES ::std::ranges::

// We use the stdext (standard extension) namespace to contain extensions that are not part of the current standard
#define _STDEXT_BEGIN namespace stdext {
#define _STDEXT_END }
#define _STDEXT ::stdext::
#define _STDEXT_BEGIN \
_EXTERN_CXX_WORKAROUND \
namespace stdext {
#define _STDEXT_END \
} \
_END_EXTERN_CXX_WORKAROUND

#define _STDEXT ::stdext::

#define _CSTD ::

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ def getBuildSteps(self, test, litConfig, shared):
testCpp = test.getSourcePath()
sourceDir = os.path.dirname(testCpp)
test2Cpp = os.path.join(sourceDir, 'test2.cpp')
test3Cpp = os.path.join(sourceDir, 'test3.cpp')
test4Cpp = os.path.join(sourceDir, 'test4.cpp')
classicCpp = os.path.join(sourceDir, 'classic.cpp')

# Dependency order is important here:
inputPaths = [stdIxx, stdCompatIxx, testCpp, test2Cpp, classicCpp]
inputPaths = [stdIxx, stdCompatIxx, testCpp, test2Cpp, test3Cpp, test4Cpp, classicCpp]

cmd = [test.cxx, *inputPaths, *test.flags, *test.compileFlags]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ ()
my $stdCompatIxx = "$stlModulesDir\\std.compat.ixx";

# Dependency order is important here:
my @inputPaths = ($stdIxx, $stdCompatIxx, "test.cpp", "test2.cpp", "classic.cpp");
my @inputPaths = ($stdIxx, $stdCompatIxx, "test.cpp", "test2.cpp", "test3.cpp", "test4.cpp", "classic.cpp");

Run::ExecuteCL(join(" ", @inputPaths, "/Fe$cwd.exe"));
}
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P2465R3_standard_library_modules/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ import std;
void prepare_test_environment();
void all_std_cmeow_tests();
void test_module_std_compat();
void test_include_all_then_import_std();
void test_include_all_then_import_std_compat();

int main() {
prepare_test_environment(); // defined in classic.cpp
all_cpp_header_tests(); // defined in test_header_units_and_modules.hpp
all_std_cmeow_tests(); // defined below
test_module_std_compat(); // defined in test2.cpp
test_include_all_then_import_std(); // defined in test3.cpp
test_include_all_then_import_std_compat(); // defined in test4.cpp
}

void test_std_cassert() {
Expand Down
30 changes: 30 additions & 0 deletions tests/std/tests/P2465R3_standard_library_modules/test3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifdef _MSVC_INTERNAL_TESTING // TRANSITION, VS 2022 17.9 Preview 3
#include <__msvc_all_public_headers.hpp>
#else // ^^^ no workaround / workaround vvv
#include <assert.h> // intentionally not <cassert>
#endif // ^^^ workaround ^^^

import std;

// INTENTIONALLY AVOIDED: using namespace std;

void test_include_all_then_import_std() {
// Verify that std::vector and std::ranges algorithms are available:
std::vector<int> v{31, 41, 59, 26, 53, 58, 97, 93};
assert(!std::ranges::is_sorted(v));
std::ranges::sort(v);
assert(std::ranges::is_sorted(v));
const std::vector<int> sorted{26, 31, 41, 53, 58, 59, 93, 97};
assert(v == sorted);

// Verify that the Sufficient Additional Overloads are available for std::sqrt():
assert(std::sqrt(25.0) == 5.0);
assert(std::sqrt(25.0f) == 5.0f);
assert(std::sqrt(25) == 5.0);
static_assert(std::is_same_v<decltype(std::sqrt(25.0)), double>);
static_assert(std::is_same_v<decltype(std::sqrt(25.0f)), float>);
static_assert(std::is_same_v<decltype(std::sqrt(25)), double>);
}
38 changes: 38 additions & 0 deletions tests/std/tests/P2465R3_standard_library_modules/test4.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifdef _MSVC_INTERNAL_TESTING // TRANSITION, VS 2022 17.9 Preview 3
#include <__msvc_all_public_headers.hpp>
#else // ^^^ no workaround / workaround vvv
#include <assert.h> // intentionally not <cassert>
#endif // ^^^ workaround ^^^

import std.compat;

// INTENTIONALLY AVOIDED: using namespace std;

void test_include_all_then_import_std_compat() {
// Verify that std::vector and std::ranges algorithms are available:
std::vector<int> v{31, 41, 59, 26, 53, 58, 97, 93};
assert(!std::ranges::is_sorted(v));
std::ranges::sort(v);
assert(std::ranges::is_sorted(v));
const std::vector<int> sorted{26, 31, 41, 53, 58, 59, 93, 97};
assert(v == sorted);

// Verify that the Sufficient Additional Overloads are available for std::sqrt():
assert(std::sqrt(25.0) == 5.0);
assert(std::sqrt(25.0f) == 5.0f);
assert(std::sqrt(25) == 5.0);
static_assert(std::is_same_v<decltype(std::sqrt(25.0)), double>);
static_assert(std::is_same_v<decltype(std::sqrt(25.0f)), float>);
static_assert(std::is_same_v<decltype(std::sqrt(25)), double>);

// Verify that the Sufficient Additional Overloads are available for ::sqrt():
assert(::sqrt(25.0) == 5.0);
assert(::sqrt(25.0f) == 5.0f);
assert(::sqrt(25) == 5.0);
static_assert(std::is_same_v<decltype(::sqrt(25.0)), double>);
static_assert(std::is_same_v<decltype(::sqrt(25.0f)), float>);
static_assert(std::is_same_v<decltype(::sqrt(25)), double>);
}

0 comments on commit 46843b3

Please sign in to comment.