Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extern "C++" as a temporary workaround for #include/import coexistence #4154

Merged
merged 4 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
26 changes: 19 additions & 7 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -4518,6 +4518,18 @@ _OutCtgIt _Copy_memmove_n(_CtgIt _First, const size_t _Count, _OutCtgIt _Dest) {
template <class _It, bool _RequiresMutable = false>
_INLINE_VAR constexpr bool _Is_vb_iterator = false;

template <class _VbIt, class _OutIt>
_CONSTEXPR20 _OutIt _Copy_vbool(_VbIt _First, _VbIt _Last, _OutIt _Dest);

template <class _VbIt>
_NODISCARD _CONSTEXPR20 _Iter_diff_t<_VbIt> _Count_vbool(_VbIt _First, _VbIt _Last, bool _Val) noexcept;

template <class _VbIt>
_CONSTEXPR20 void _Fill_vbool(_VbIt _First, _VbIt _Last, bool _Val) noexcept;

template <class _VbIt>
_NODISCARD _CONSTEXPR20 _VbIt _Find_vbool(_VbIt _First, _VbIt _Last, bool _Val) noexcept;

template <class _InIt, class _SizeTy, class _OutIt>
_CONSTEXPR20 _OutIt _Copy_n_unchecked4(_InIt _First, _SizeTy _Count, _OutIt _Dest) {
// copy _First + [0, _Count) to _Dest + [0, _Count), returning _Dest + _Count
Expand Down Expand Up @@ -4556,7 +4568,7 @@ _CONSTEXPR20 _OutIt _Copy_unchecked(_InIt _First, _Sent _Last, _OutIt _Dest) {
// copy [_First, _Last) to [_Dest, ...)
// note: _Copy_unchecked has callers other than the copy family
if constexpr (_Is_vb_iterator<_InIt> && _Is_vb_iterator<_OutIt, true>) {
return _Copy_vbool(_First, _Last, _Dest);
return _STD _Copy_vbool(_First, _Last, _Dest);
} else {
if constexpr (_Sent_copy_cat<_InIt, _Sent, _OutIt>::_Bitcopy_assignable) {
#if _HAS_CXX20
Expand Down Expand Up @@ -4753,7 +4765,7 @@ _CONSTEXPR20 _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) {
_Algorithm_int_t<_Diff> _Count = _Count_raw;
if (0 < _Count) {
if constexpr (_Is_vb_iterator<_InIt> && _Is_vb_iterator<_OutIt, true>) {
return _Copy_vbool(_First, _First + _Count, _Dest);
return _STD _Copy_vbool(_First, _First + _Count, _Dest);
} else {
auto _UFirst = _Get_unwrapped_n(_First, _Count);
auto _UDest = _Get_unwrapped_n(_Dest, _Count);
Expand Down Expand Up @@ -4856,7 +4868,7 @@ _CONSTEXPR20 _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) {
// move [_First, _Last) to [_Dest, ...)
// note: _Move_unchecked has callers other than the move family
if constexpr (_Is_vb_iterator<_InIt> && _Is_vb_iterator<_OutIt, true>) {
return _Copy_vbool(_First, _Last, _Dest);
return _STD _Copy_vbool(_First, _Last, _Dest);
} else {
if constexpr (_Iter_move_cat<_InIt, _OutIt>::_Bitcopy_assignable) {
#if _HAS_CXX20
Expand Down Expand Up @@ -5006,7 +5018,7 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val)
// copy _Val through [_First, _Last)
_Adl_verify_range(_First, _Last);
if constexpr (_Is_vb_iterator<_FwdIt, true>) {
_Fill_vbool(_First, _Last, _Val);
_STD _Fill_vbool(_First, _Last, _Val);
} else {
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
Expand Down Expand Up @@ -5048,7 +5060,7 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val
if (0 < _Count) {
if constexpr (_Is_vb_iterator<_OutIt, true>) {
const auto _Last = _Dest + static_cast<typename _OutIt::difference_type>(_Count);
_Fill_vbool(_Dest, _Last, _Val);
_STD _Fill_vbool(_Dest, _Last, _Val);
return _Last;
} else {
auto _UDest = _Get_unwrapped_n(_Dest, _Count);
Expand Down Expand Up @@ -5814,7 +5826,7 @@ _EXPORT_STD template <class _InIt, class _Ty>
_NODISCARD _CONSTEXPR20 _InIt find(_InIt _First, const _InIt _Last, const _Ty& _Val) { // find first matching _Val
_Adl_verify_range(_First, _Last);
if constexpr (_Is_vb_iterator<_InIt> && is_same_v<_Ty, bool>) {
return _Find_vbool(_First, _Last, _Val);
return _STD _Find_vbool(_First, _Last, _Val);
} else {
_Seek_wrapped(_First, _STD _Find_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Val));
return _First;
Expand Down Expand Up @@ -5944,7 +5956,7 @@ _NODISCARD _CONSTEXPR20 _Iter_diff_t<_InIt> count(const _InIt _First, const _InI
// count elements that match _Val
_Adl_verify_range(_First, _Last);
if constexpr (_Is_vb_iterator<_InIt> && is_same_v<_Ty, bool>) {
return _Count_vbool(_First, _Last, _Val);
return _STD _Count_vbool(_First, _Last, _Val);
} else {
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
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.
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved

#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>);
}
Loading