diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 48f056d3c2..5dff5d77f1 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -37,14 +37,14 @@ struct _Conjunction { // handle false trait or last trait template struct _Conjunction { // the first trait is true, try the next one - using type = typename _Conjunction<_Next::value, _Next, _Rest...>::type; + using type = typename _Conjunction(_Next::value), _Next, _Rest...>::type; }; _EXPORT_STD template struct conjunction : true_type {}; // If _Traits is empty, true_type template -struct conjunction<_First, _Rest...> : _Conjunction<_First::value, _First, _Rest...>::type { +struct conjunction<_First, _Rest...> : _Conjunction(_First::value), _First, _Rest...>::type { // the first false trait in _Traits, or the last trait if none are false }; diff --git a/stl/inc/xtr1common b/stl/inc/xtr1common index 02ea58bc09..b1829b8b32 100644 --- a/stl/inc/xtr1common +++ b/stl/inc/xtr1common @@ -152,14 +152,14 @@ struct _Disjunction { // handle true trait or last trait template struct _Disjunction { // first trait is false, try the next trait - using type = typename _Disjunction<_Next::value, _Next, _Rest...>::type; + using type = typename _Disjunction(_Next::value), _Next, _Rest...>::type; }; _EXPORT_STD template struct disjunction : false_type {}; // If _Traits is empty, false_type template -struct disjunction<_First, _Rest...> : _Disjunction<_First::value, _First, _Rest...>::type { +struct disjunction<_First, _Rest...> : _Disjunction(_First::value), _First, _Rest...>::type { // the first true trait in _Traits, or the last trait if none are true }; diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 5ae8f27917..d3dc676d06 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -370,6 +370,12 @@ std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp:1 FAIL std/language.support/support.rtti/type.info/type_info.equal.pass.cpp:0 FAIL std/language.support/support.rtti/type.info/type_info.equal.pass.cpp:1 FAIL +# VSO-2170500 C1XX's type trait optimization mishandles conjunction/disjunction with non-bool types +std/utilities/meta/meta.logical/conjunction.compile.pass.cpp:0 FAIL +std/utilities/meta/meta.logical/conjunction.compile.pass.cpp:1 FAIL +std/utilities/meta/meta.logical/disjunction.compile.pass.cpp:0 FAIL +std/utilities/meta/meta.logical/disjunction.compile.pass.cpp:1 FAIL + # *** CLANG COMPILER BUGS *** # LLVM-46207 Clang's tgmath.h interferes with the UCRT's tgmath.h @@ -905,12 +911,6 @@ std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass # Not analyzed. Checking whether packaged_task is constructible from an allocator and a packaged_task of a different type. std/thread/futures/futures.task/futures.task.members/ctor2.compile.pass.cpp FAIL -# Not analyzed. -# MSVC warning C4305: 'specialization': truncation from 'const int' to 'bool' -# Clang error: non-type template argument evaluates to -1, which cannot be narrowed to type 'bool' [-Wc++11-narrowing] -std/utilities/meta/meta.logical/conjunction.compile.pass.cpp FAIL -std/utilities/meta/meta.logical/disjunction.compile.pass.cpp FAIL - # Not analyzed. Possible MSVC compiler bug, this is inspecting type trait behavior. std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_copy_assignable.pass.cpp:0 FAIL std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_copy_assignable.pass.cpp:1 FAIL diff --git a/tests/std/test.lst b/tests/std/test.lst index 4631d566e5..94359ef750 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -247,6 +247,7 @@ tests\GH_004609_heterogeneous_cmp_overloads tests\GH_004618_mixed_operator_usage_keeps_statistical_properties tests\GH_004618_normal_distribution_avoids_resets tests\GH_004657_expected_constraints_permissive +tests\GH_004845_logical_operator_traits_with_non_bool_constant tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function diff --git a/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/env.lst b/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/env.lst new file mode 100644 index 0000000000..19f025bd0e --- /dev/null +++ b/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/test.compile.pass.cpp b/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/test.compile.pass.cpp new file mode 100644 index 0000000000..0f621d7f99 --- /dev/null +++ b/tests/std/tests/GH_004845_logical_operator_traits_with_non_bool_constant/test.compile.pass.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// GH-4845 : Logical operator traits with non-bool_constant arguments emit truncation warnings + +#include +using namespace std; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +template +void test_base_derived() { + STATIC_ASSERT(is_base_of_v); + using ValueType = typename Base::value_type; + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(Base::value == Derived::type::value); +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-2170500 (C1XX type trait optimization) + STATIC_ASSERT(is_same_v); + STATIC_ASSERT(Base::value == Derived::value); +#endif // ^^^ no workaround ^^^ +} + +template +using SC = integral_constant; +template +using LC = integral_constant; + +// This test is verifying the absence of truncation warnings, so it uses integral values of 2 or greater for "true" +// values, skipping 1. It also tests these values in both the "first" and "next" positions, as they were both affected. + +void test_conjunction() { + // N4986 [meta.logical]/5: + // The specialization conjunction has a public and unambiguous base that is either + // - the first type Bi in the list true_type, B1, ..., BN for which bool(Bi::value) is false, or + // - if there is no such Bi, the last type in the list. + test_base_derived, conjunction, LC<3>>>(); + test_base_derived, conjunction, LC<0>>>(); + test_base_derived, conjunction, LC<5>>>(); + test_base_derived, conjunction, LC<0>>>(); +} + +void test_disjunction() { + // N4986 [meta.logical]/10: + // The specialization disjunction has a public and unambiguous base that is either + // - the first type Bi in the list false_type, B1, ..., BN for which bool(Bi::value) is true, or + // - if there is no such Bi, the last type in the list. + test_base_derived, disjunction, LC<7>>>(); + test_base_derived, disjunction, LC<0>>>(); + test_base_derived, disjunction, LC<9>>>(); + test_base_derived, disjunction, LC<0>>>(); +} + +void test_negation() { + // N4986 [meta.logical]/12: + // The class template negation forms the logical negation of its template type argument. + // The type negation is a Cpp17UnaryTypeTrait with a base characteristic of bool_constant. + test_base_derived>>(); + test_base_derived>>(); +}