Add `[[msvc::lifetimebound]]` to `minmax` (#3831)

Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
This commit is contained in:
statementreply 2023-07-14 09:43:51 +08:00 коммит произвёл GitHub
Родитель f155b411f2
Коммит 7c7cc0c13d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 82 добавлений и 7 удалений

Просмотреть файл

@ -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 <class _Ty, class _Pr>
_NODISCARD constexpr pair<const _Ty&, const _Ty&> minmax(const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept(
noexcept(_DEBUG_LT_PRED(_Pred, _Right, _Left))) /* strengthened */ {
_NODISCARD constexpr pair<const _Ty&, const _Ty&> 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 <class _Ty>
_NODISCARD constexpr pair<const _Ty&, const _Ty&> minmax(const _Ty& _Left, const _Ty& _Right) noexcept(
noexcept(_Right < _Left)) /* strengthened */ {
_NODISCARD constexpr pair<const _Ty&, const _Ty&> 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 <class _Ty, class _Pj = identity,
indirect_strict_weak_order<projected<const _Ty*, _Pj>> _Pr = ranges::less>
_NODISCARD constexpr minmax_result<const _Ty&> operator()(
const _Ty& _Left, const _Ty& _Right, _Pr _Pred = {}, _Pj _Proj = {}) const {
_NODISCARD constexpr minmax_result<const _Ty&> 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)

Просмотреть файл

@ -664,10 +664,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
@ -701,7 +703,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")

Просмотреть файл

@ -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@'

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation. -->
<!-- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -->
<RuleSet Name="STL Ruleset" Description="C++ Core Guidelines rules for microsoft/STL" ToolsVersion="15.0">
<Rules AnalyzerId="Microsoft.Analyzers.NativeCodeAnalysis" RuleNamespace="Microsoft.Rules.Native">
<!-- The pointer is dangling because it points at a temporary instance that was destroyed. (ES.65) -->
<Rule Id="C26815" Action="Warning" />
<!-- The pointer points to memory allocated on the stack (ES.65) -->
<Rule Id="C26816" Action="Warning" />
</Rules>
</RuleSet>

Просмотреть файл

@ -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

Просмотреть файл

@ -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-"

Просмотреть файл

@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <__msvc_all_public_headers.hpp>

Просмотреть файл

@ -145,7 +145,7 @@ class STLTestFormat:
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

Просмотреть файл

@ -38,6 +38,7 @@ class STLTest(Test):
def configureTest(self, litConfig):
self.compileFlags = []
self.cxx = None
self.env = {}
self.fileDependencies = []
self.flags = []
self.isenseRspPath = None
@ -234,7 +235,13 @@ class STLTest(Test):
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 @@ class STLTest(Test):
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 @@ class STLTest(Test):
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):