diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 298f1439d03..ba137d5fefb 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -177,6 +177,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/semaphore ${CMAKE_CURRENT_LIST_DIR}/inc/set ${CMAKE_CURRENT_LIST_DIR}/inc/shared_mutex + ${CMAKE_CURRENT_LIST_DIR}/inc/source_location ${CMAKE_CURRENT_LIST_DIR}/inc/span ${CMAKE_CURRENT_LIST_DIR}/inc/sstream ${CMAKE_CURRENT_LIST_DIR}/inc/stack diff --git a/stl/inc/__msvc_all_public_headers.hpp b/stl/inc/__msvc_all_public_headers.hpp index 65b45f62770..9889036b41b 100644 --- a/stl/inc/__msvc_all_public_headers.hpp +++ b/stl/inc/__msvc_all_public_headers.hpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json index 66cb2996698..d33b9abc629 100644 --- a/stl/inc/header-units.json +++ b/stl/inc/header-units.json @@ -87,6 +87,7 @@ "semaphore", "set", "shared_mutex", + "source_location", "span", "sstream", "stack", diff --git a/stl/inc/source_location b/stl/inc/source_location new file mode 100644 index 00000000000..a9e6154c44f --- /dev/null +++ b/stl/inc/source_location @@ -0,0 +1,66 @@ +// source_location standard header (core) + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once +#ifndef _SOURCE_LOCATION_ +#define _SOURCE_LOCATION_ +#include +#if _STL_COMPILER_PREPROCESSOR +#ifndef __cpp_consteval +#pragma message("The contents of are available only with C++20 consteval support.") +#else // ^^^ !defined(__cpp_consteval) / defined(__cpp_consteval) vvv + +#include + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +_STD_BEGIN +struct source_location { + _NODISCARD static consteval source_location current(const uint_least32_t _Line_ = __builtin_LINE(), + const uint_least32_t _Column_ = __builtin_COLUMN(), const char* const _File_ = __builtin_FILE(), + const char* const _Function_ = __builtin_FUNCTION()) noexcept { + source_location _Result; + _Result._Line = _Line_; + _Result._Column = _Column_; + _Result._File = _File_; + _Result._Function = _Function_; + return _Result; + } + + _NODISCARD_CTOR constexpr source_location() noexcept = default; + + _NODISCARD constexpr uint_least32_t line() const noexcept { + return _Line; + } + _NODISCARD constexpr uint_least32_t column() const noexcept { + return _Column; + } + _NODISCARD constexpr const char* file_name() const noexcept { + return _File; + } + _NODISCARD constexpr const char* function_name() const noexcept { + return _Function; + } + +private: + uint_least32_t _Line{}; + uint_least32_t _Column{}; + const char* _File = ""; + const char* _Function = ""; +}; +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // !defined(__cpp_consteval) +#endif // _STL_COMPILER_PREPROCESSOR +#endif // _SOURCE_LOCATION_ diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index d687c20516e..f6d819761f7 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -202,6 +202,7 @@ // P1135R6 The C++20 Synchronization Library // P1207R4 Movability Of Single-Pass Iterators // (partially implemented) +// P1208R6 // P1209R0 erase_if(), erase() // P1227R2 Signed std::ssize(), Unsigned span::size() // P1243R4 Rangify New Algorithms @@ -1255,10 +1256,15 @@ #define __cpp_lib_semaphore 201907L #define __cpp_lib_shift 201806L #define __cpp_lib_smart_ptr_for_overwrite 202002L -#define __cpp_lib_span 202002L -#define __cpp_lib_ssize 201902L -#define __cpp_lib_starts_ends_with 201711L -#define __cpp_lib_syncbuf 201803L + +#ifdef __cpp_consteval +#define __cpp_lib_source_location 201907L +#endif // __cpp_consteval + +#define __cpp_lib_span 202002L +#define __cpp_lib_ssize 201902L +#define __cpp_lib_starts_ends_with 201711L +#define __cpp_lib_syncbuf 201803L #ifdef __cpp_lib_concepts // TRANSITION, GH-395 #define __cpp_lib_three_way_comparison 201907L diff --git a/tests/std/test.lst b/tests/std/test.lst index cd16f4d0e15..e5866c93af1 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -401,6 +401,7 @@ tests\P1135R6_barrier tests\P1135R6_latch tests\P1135R6_semaphore tests\P1165R1_consistently_propagating_stateful_allocators +tests\P1208R6_source_location tests\P1423R3_char8_t_remediation tests\P1502R1_standard_library_header_units tests\P1614R2_spaceship diff --git a/tests/std/tests/P1208R6_source_location/env.lst b/tests/std/tests/P1208R6_source_location/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P1208R6_source_location/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P1208R6_source_location/header.h b/tests/std/tests/P1208R6_source_location/header.h new file mode 100644 index 00000000000..a16d321ee66 --- /dev/null +++ b/tests/std/tests/P1208R6_source_location/header.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once +#include +#include +#include + +constexpr void header_test() { + using namespace std; + const auto x = source_location::current(); + assert(x.line() == __LINE__ - 1); + assert(x.column() == 37); + assert(x.function_name() == "header_test"sv); + assert(string_view{x.file_name()}.ends_with("header.h"sv)); +} diff --git a/tests/std/tests/P1208R6_source_location/test.cpp b/tests/std/tests/P1208R6_source_location/test.cpp new file mode 100644 index 00000000000..547c0b7130a --- /dev/null +++ b/tests/std/tests/P1208R6_source_location/test.cpp @@ -0,0 +1,160 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#if defined(__cpp_consteval) && !defined(__EDG__) // TRANSITION, VSO-1285779 +#include "header.h" +#include +#include +#include +#include +using namespace std; + +static_assert(is_nothrow_default_constructible_v); +static_assert(is_nothrow_move_constructible_v); +static_assert(is_nothrow_move_assignable_v); +static_assert(is_nothrow_swappable_v); + +constexpr auto test_cpp = "test.cpp"sv; + +constexpr auto g = source_location::current(); +static_assert(g.line() == __LINE__ - 1); +static_assert(g.column() == 37); +static_assert(g.function_name() == ""sv); +static_assert(string_view{g.file_name()}.ends_with(test_cpp)); + +constexpr int s_int_line = __LINE__ + 3; +struct s { + constexpr s(const source_location x = source_location::current()) : loc(x) {} + constexpr s(int) {} + source_location loc = source_location::current(); +}; + +constexpr int s2_int_line = __LINE__ + 3; +struct s2 { + constexpr s2(const source_location l = source_location::current()) : x{l} {} + constexpr s2(int) {} + s x = source_location::current(); +}; + +constexpr void copy_test() { + const auto rhs = source_location::current(); + const auto lhs = rhs; + assert(lhs.line() == rhs.line()); + assert(lhs.column() == rhs.column()); + assert(string_view{lhs.function_name()} == string_view{rhs.function_name()}); + assert(string_view{lhs.file_name()} == string_view{rhs.file_name()}); +} + +constexpr void local_test() { + const auto x = source_location::current(); + assert(x.line() == __LINE__ - 1); + assert(x.column() == 37); + assert(x.function_name() == "local_test"sv); + assert(string_view{x.file_name()}.ends_with(test_cpp)); +} + +constexpr void argument_test( + const unsigned int line, const unsigned int column, const source_location x = source_location::current()) { + assert(x.line() == line); + assert(x.column() == column); + assert(x.function_name() == "test"sv); + assert(string_view{x.file_name()}.ends_with(test_cpp)); +} + +constexpr void sloc_constructor_test() { + const s x; + assert(x.loc.line() == __LINE__ - 1); +#ifdef _PREFAST_ + assert(x.loc.column() == 14); +#else // _PREFAST_ + assert(x.loc.column() == 13); +#endif // _PREFAST_ + if (is_constant_evaluated()) { + assert(x.loc.function_name() == "main"sv); // TRANSITION, VSO-1285783 + } else { + assert(x.loc.function_name() == "sloc_constructor_test"sv); + } + assert(string_view{x.loc.file_name()}.ends_with(test_cpp)); +} + +constexpr void different_constructor_test() { + const s x{1}; + assert(x.loc.line() == s_int_line); + assert(x.loc.column() == 5); + assert(x.loc.function_name() == "s"sv); + assert(string_view{x.loc.file_name()}.ends_with(test_cpp)); +} + +constexpr void sub_member_test() { + const s2 s; + assert(s.x.loc.line() == __LINE__ - 1); +#ifdef _PREFAST_ + assert(s.x.loc.column() == 15); +#else // _PREFAST_ + assert(s.x.loc.column() == 14); +#endif // _PREFAST_ + if (is_constant_evaluated()) { + assert(s.x.loc.function_name() == "main"sv); // TRANSITION, VSO-1285783 + } else { + assert(s.x.loc.function_name() == "sub_member_test"sv); + } + assert(string_view{s.x.loc.file_name()}.ends_with(test_cpp)); + + const s2 s_i{1}; + assert(s_i.x.loc.line() == s2_int_line); + assert(s_i.x.loc.column() == 5); + assert(s_i.x.loc.function_name() == "s2"sv); + assert(string_view{s_i.x.loc.file_name()}.ends_with(test_cpp)); +} + +constexpr void lambda_test() { + const auto l = [loc = source_location::current()] { return loc; }; + const auto x = l(); + assert(x.line() == __LINE__ - 2); + assert(x.column() == 51); + assert(x.function_name() == "lambda_test"sv); + assert(string_view{x.file_name()}.ends_with(test_cpp)); +} + +template +constexpr source_location function_template() { + return source_location::current(); +} + +constexpr void function_template_test() { + const auto x1 = function_template(); + assert(x1.line() == __LINE__ - 5); + assert(x1.column() == 29); + assert(x1.function_name() == "function_template"sv); + assert(string_view{x1.file_name()}.ends_with(test_cpp)); + + const auto x2 = function_template(); + assert(x1.line() == x2.line()); + assert(x1.column() == x2.column()); + assert(string_view{x1.function_name()} == string_view{x2.function_name()}); + assert(string_view{x1.file_name()} == string_view{x2.file_name()}); +} + +constexpr bool test() { + copy_test(); + local_test(); + argument_test(__LINE__, 5); + const auto loc = source_location::current(); + argument_test(__LINE__ - 1, 39, loc); + sloc_constructor_test(); + different_constructor_test(); + sub_member_test(); + lambda_test(); + function_template_test(); + header_test(); + return true; +} + +int main() { + test(); + static_assert(test()); + return 0; +} +#else // ^^^ defined(__cpp_consteval) && !defined(__EDG__) / !defined(__cpp_consteval) || defined(__EDG__) vvv +int main() {} +#endif // ^^^ !defined(__cpp_consteval) || defined(__EDG__) ^^^ diff --git a/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py b/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py index ddf75ebbd8d..d86678b8fd0 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py +++ b/tests/std/tests/P1502R1_standard_library_header_units/custom_format.py @@ -63,7 +63,7 @@ def getBuildSteps(self, test, litConfig, shared): 'semaphore', 'set', 'shared_mutex', - # 'source_location', + 'source_location', 'span', 'sstream', 'stack', diff --git a/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl b/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl index 2ccde3fc6e8..37dff666bd4 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl +++ b/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl @@ -62,7 +62,7 @@ () "semaphore", "set", "shared_mutex", - # "source_location", + "source_location", "span", "sstream", "stack", diff --git a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp index 575412397c5..2a1a084eb7b 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp +++ b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp @@ -63,7 +63,7 @@ import ; import ; import ; import ; -// import ; +import ; import ; import ; import ; @@ -94,6 +94,17 @@ import ; #include using namespace std; +constexpr bool test_source_location() { +#ifdef __cpp_lib_source_location + const auto sl = source_location::current(); + assert(sl.line() == __LINE__ - 1); + assert(sl.column() == 1); + assert(sl.function_name() == "test_source_location"sv); + assert(string_view{sl.file_name()}.ends_with("test.cpp"sv)); +#endif // __cpp_lib_source_location + return true; +} + int main() { { puts("Testing ."); @@ -689,7 +700,8 @@ int main() { { puts("Testing ."); - puts("(TRANSITION, not yet implemented.)"); + assert(test_source_location()); + static_assert(test_source_location()); } { diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index fae3753143c..7fad05d2151 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1353,6 +1353,20 @@ STATIC_ASSERT(__cpp_lib_smart_ptr_for_overwrite == 202002L); #endif #endif +#if _HAS_CXX20 && defined(__cpp_consteval) +#ifndef __cpp_lib_source_location +#error __cpp_lib_source_location is not defined +#elif __cpp_lib_source_location != 201907L +#error __cpp_lib_source_location is not 201907L +#else +STATIC_ASSERT(__cpp_lib_source_location == 201907L); +#endif +#else +#ifdef __cpp_lib_source_location +#error __cpp_lib_source_location is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_span #error __cpp_lib_span is not defined diff --git a/tests/std/tests/include_each_header_alone_matrix.lst b/tests/std/tests/include_each_header_alone_matrix.lst index 1a7ff0a6cd4..504b759ef6d 100644 --- a/tests/std/tests/include_each_header_alone_matrix.lst +++ b/tests/std/tests/include_each_header_alone_matrix.lst @@ -3,6 +3,7 @@ RUNALL_INCLUDE .\prefix.lst RUNALL_CROSSLIST +PM_CL="/DNO_TEST_ENVIRONMENT_PREPARER /EHsc /MTd /std:c++latest /permissive- /fp:strict /w14640 /Zc:threadSafeInit-" PM_COMPILER="clang-cl" PM_CL="/DNO_TEST_ENVIRONMENT_PREPARER -fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MTd /std:c++latest /permissive- /fp:strict /w14640 /Zc:threadSafeInit-" RUNALL_CROSSLIST PM_CL="/DMEOW_HEADER=algorithm" @@ -58,6 +59,7 @@ PM_CL="/DMEOW_HEADER=scoped_allocator" PM_CL="/DMEOW_HEADER=semaphore" PM_CL="/DMEOW_HEADER=set" PM_CL="/DMEOW_HEADER=shared_mutex" +PM_CL="/DMEOW_HEADER=source_location" PM_CL="/DMEOW_HEADER=span" PM_CL="/DMEOW_HEADER=sstream" PM_CL="/DMEOW_HEADER=stack"