diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 7a8f91dc1aa..466fbf25731 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -21,6 +21,12 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new +// TRANSITION, non-_Ugly attribute tokens +#pragma push_macro("msvc") +#pragma push_macro("lifetimebound") +#undef msvc +#undef lifetimebound + #if _USE_STD_VECTOR_ALGORITHMS _EXTERN_C @@ -10003,8 +10009,9 @@ namespace ranges { #endif // _HAS_CXX17 _EXPORT_STD template -_NODISCARD constexpr pair minmax(const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept( - noexcept(_DEBUG_LT_PRED(_Pred, _Right, _Left))) /* strengthened */ { +_NODISCARD constexpr pair minmax(const _Ty& _Left _MSVC_LIFETIMEBOUND, + const _Ty& _Right _MSVC_LIFETIMEBOUND, + _Pr _Pred) noexcept(noexcept(_DEBUG_LT_PRED(_Pred, _Right, _Left))) /* strengthened */ { // return pair(leftmost/smaller, rightmost/larger) of _Left and _Right if (_DEBUG_LT_PRED(_Pred, _Right, _Left)) { return {_Right, _Left}; @@ -10021,8 +10028,8 @@ _NODISCARD constexpr pair<_Ty, _Ty> minmax(initializer_list<_Ty> _Ilist, _Pr _Pr } _EXPORT_STD template -_NODISCARD constexpr pair minmax(const _Ty& _Left, const _Ty& _Right) noexcept( - noexcept(_Right < _Left)) /* strengthened */ { +_NODISCARD constexpr pair minmax(const _Ty& _Left _MSVC_LIFETIMEBOUND, + const _Ty& _Right _MSVC_LIFETIMEBOUND) noexcept(noexcept(_Right < _Left)) /* strengthened */ { // return pair(leftmost/smaller, rightmost/larger) of _Left and _Right if (_Right < _Left) { _STL_ASSERT(!(_Left < _Right), "invalid comparator"); @@ -10049,8 +10056,8 @@ namespace ranges { template > _Pr = ranges::less> - _NODISCARD constexpr minmax_result operator()( - const _Ty& _Left, const _Ty& _Right, _Pr _Pred = {}, _Pj _Proj = {}) const { + _NODISCARD constexpr minmax_result operator()(const _Ty& _Left _MSVC_LIFETIMEBOUND, + const _Ty& _Right _MSVC_LIFETIMEBOUND, _Pr _Pred = {}, _Pj _Proj = {}) const { if (_STD invoke(_Pred, _STD invoke(_Proj, _Right), _STD invoke(_Proj, _Left))) { return {_Right, _Left}; } else { @@ -10673,6 +10680,11 @@ namespace ranges { #endif // _HAS_CXX17 _STD_END + +// TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("lifetimebound") +#pragma pop_macro("msvc") + #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index ceb2fce5ed8..302292aacd2 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -663,10 +663,12 @@ #pragma push_macro("known_semantics") #pragma push_macro("noop_dtor") #pragma push_macro("intrinsic") +#pragma push_macro("lifetimebound") #undef msvc #undef known_semantics #undef noop_dtor #undef intrinsic +#undef lifetimebound #ifndef __has_cpp_attribute #define _HAS_MSVC_ATTRIBUTE(x) 0 @@ -700,7 +702,19 @@ #define _MSVC_INTRINSIC #endif +// Should we enable [[msvc::lifetimebound]] or [[clang::lifetimebound]] warnings? +#if !defined(__has_cpp_attribute) || defined(_SILENCE_LIFETIMEBOUND_WARNING) +#define _MSVC_LIFETIMEBOUND +#elif _HAS_MSVC_ATTRIBUTE(lifetimebound) +#define _MSVC_LIFETIMEBOUND [[msvc::lifetimebound]] +#elif __has_cpp_attribute(_Clang::__lifetimebound__) +#define _MSVC_LIFETIMEBOUND [[_Clang::__lifetimebound__]] +#else +#define _MSVC_LIFETIMEBOUND +#endif + #undef _HAS_MSVC_ATTRIBUTE +#pragma pop_macro("lifetimebound") #pragma pop_macro("intrinsic") #pragma pop_macro("noop_dtor") #pragma pop_macro("known_semantics") diff --git a/tests/std/lit.site.cfg.in b/tests/std/lit.site.cfg.in index 78cdb1a7130..9941c44e79c 100644 --- a/tests/std/lit.site.cfg.in +++ b/tests/std/lit.site.cfg.in @@ -19,12 +19,14 @@ config.test_format = stl.test.format.STLTestFormat() lit_config.expected_results = getattr(lit_config, 'expected_results', dict()) lit_config.include_dirs = getattr(lit_config, 'include_dirs', dict()) lit_config.library_dirs = getattr(lit_config, 'library_dirs', dict()) +lit_config.ruleset_dirs = getattr(lit_config, 'ruleset_dirs', dict()) lit_config.test_subdirs = getattr(lit_config, 'test_subdirs', dict()) lit_config.expected_results[config.name] = stl.test.file_parsing.parse_result_file('@STD_EXPECTED_RESULTS@') lit_config.include_dirs[config.name] = \ ['@STL_TESTED_HEADERS_DIR@', '@LIBCXX_SOURCE_DIR@/test/support', '@STL_SOURCE_DIR@/tests/std/include'] lit_config.library_dirs[config.name] = ['@STL_LIBRARY_OUTPUT_DIRECTORY@', '@TOOLSET_LIB@'] +lit_config.ruleset_dirs[config.name] = ['@STL_SOURCE_DIR@/tests/std/rulesets'] lit_config.test_subdirs[config.name] = ['@CMAKE_CURRENT_SOURCE_DIR@/tests'] lit_config.cxx_headers = '@STL_TESTED_HEADERS_DIR@' diff --git a/tests/std/rulesets/stl.ruleset b/tests/std/rulesets/stl.ruleset new file mode 100644 index 00000000000..7859a44da86 --- /dev/null +++ b/tests/std/rulesets/stl.ruleset @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tests/std/test.lst b/tests/std/test.lst index 3059eef1402..154fa991f48 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -200,6 +200,8 @@ tests\GH_002030_asan_annotate_vector tests\GH_002039_byte_is_not_trivially_swappable tests\GH_002045_put_time_changes_errno tests\GH_002058_debug_iterator_race +# Needs special machinery to work in the MSVC-internal test harness, not yet implemented: +# tests\GH_002094_cpp_core_guidelines tests\GH_002120_streambuf_seekpos_and_seekoff tests\GH_002168_regex_overflow tests\GH_002206_unreserved_names diff --git a/tests/std/tests/GH_002094_cpp_core_guidelines/env.lst b/tests/std/tests/GH_002094_cpp_core_guidelines/env.lst new file mode 100644 index 00000000000..56a4f87e0b0 --- /dev/null +++ b/tests/std/tests/GH_002094_cpp_core_guidelines/env.lst @@ -0,0 +1,16 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\prefix.lst +RUNALL_CROSSLIST +PM_CL="/EHsc /w14640 /Zc:threadSafeInit-" +RUNALL_CROSSLIST +PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++14 /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++17 /permissive- /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++20 /permissive- /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog- /analyze:plugin EspXEngine.dll /analyze:ruleset stl.ruleset" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /MD /std:c++14" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /MDd /std:c++17" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /MT /std:c++20 /permissive-" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /MTd /std:c++latest /permissive-" diff --git a/tests/std/tests/GH_002094_cpp_core_guidelines/test.compile.pass.cpp b/tests/std/tests/GH_002094_cpp_core_guidelines/test.compile.pass.cpp new file mode 100644 index 00000000000..1132aa12357 --- /dev/null +++ b/tests/std/tests/GH_002094_cpp_core_guidelines/test.compile.pass.cpp @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include <__msvc_all_public_headers.hpp> diff --git a/tests/utils/stl/test/format.py b/tests/utils/stl/test/format.py index 7de5471eda7..096a0a7907c 100644 --- a/tests/utils/stl/test/format.py +++ b/tests/utils/stl/test/format.py @@ -145,7 +145,7 @@ class SharedState: env: Dict[str, str] = field(default_factory=dict) execDir, _ = test.getTempPaths() - shared = SharedState(None, execDir, copy.deepcopy(litConfig.test_env)) + shared = SharedState(None, execDir, _mergeEnvironments(litConfig.test_env, test.env)) shared.env['TMP'] = execDir shared.env['TEMP'] = execDir shared.env['TMPDIR'] = execDir diff --git a/tests/utils/stl/test/tests.py b/tests/utils/stl/test/tests.py index fc0b0e2fafe..21f0bb9921a 100644 --- a/tests/utils/stl/test/tests.py +++ b/tests/utils/stl/test/tests.py @@ -38,6 +38,7 @@ def __init__(self, suite, pathInSuite, litConfig, testConfig, envlstEntry, envNu def configureTest(self, litConfig): self.compileFlags = [] self.cxx = None + self.env = {} self.fileDependencies = [] self.flags = [] self.isenseRspPath = None @@ -234,7 +235,13 @@ def _addCustomFeature(self, name): def _parseFlags(self, litConfig): foundStd = False foundCRT = False + afterAnalyzePlugin = False for flag in chain(self.flags, self.compileFlags, self.linkFlags): + if afterAnalyzePlugin: + if 'EspXEngine.dll'.casefold() in flag.casefold(): + self._addCustomFeature('espxengine') + afterAnalyzePlugin = False + if flag[1:5] == 'std:': foundStd = True if flag[5:] == 'c++latest': @@ -279,6 +286,8 @@ def _parseFlags(self, litConfig): self._addCustomFeature('MT') self._addCustomFeature('static_CRT') foundCRT = True + elif flag[1:] == 'analyze:plugin': + afterAnalyzePlugin = True if not foundStd: self._addCustomFeature('c++14') @@ -294,6 +303,11 @@ def _parseFlags(self, litConfig): if 'asan' in self.config.available_features and 'clang' in self.config.available_features: self.linkFlags.append("/INFERASANLIBS") + # code analysis settings + if 'espxengine' in self.config.available_features: + self.compileFlags.extend(["/analyze:rulesetdirectory", ';'.join(litConfig.ruleset_dirs[self.config.name])]) + self.env['Esp.Extensions'] = 'CppCoreCheck.dll' + self.env['Esp.AnnotationBuildLevel'] = 'Ignore' class LibcxxTest(STLTest): def getTestName(self):