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

Fix truncation warnings in conjunction/disjunction #4846

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
4 changes: 2 additions & 2 deletions stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ struct _Conjunction { // handle false trait or last trait

template <class _True, class _Next, class... _Rest>
struct _Conjunction<true, _True, _Next, _Rest...> { // the first trait is true, try the next one
using type = typename _Conjunction<_Next::value, _Next, _Rest...>::type;
using type = typename _Conjunction<static_cast<bool>(_Next::value), _Next, _Rest...>::type;
};

_EXPORT_STD template <class... _Traits>
struct conjunction : true_type {}; // If _Traits is empty, true_type

template <class _First, class... _Rest>
struct conjunction<_First, _Rest...> : _Conjunction<_First::value, _First, _Rest...>::type {
struct conjunction<_First, _Rest...> : _Conjunction<static_cast<bool>(_First::value), _First, _Rest...>::type {
// the first false trait in _Traits, or the last trait if none are false
};

Expand Down
4 changes: 2 additions & 2 deletions stl/inc/xtr1common
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,14 @@ struct _Disjunction { // handle true trait or last trait

template <class _False, class _Next, class... _Rest>
struct _Disjunction<false, _False, _Next, _Rest...> { // first trait is false, try the next trait
using type = typename _Disjunction<_Next::value, _Next, _Rest...>::type;
using type = typename _Disjunction<static_cast<bool>(_Next::value), _Next, _Rest...>::type;
};

_EXPORT_STD template <class... _Traits>
struct disjunction : false_type {}; // If _Traits is empty, false_type

template <class _First, class... _Rest>
struct disjunction<_First, _Rest...> : _Disjunction<_First::value, _First, _Rest...>::type {
struct disjunction<_First, _Rest...> : _Disjunction<static_cast<bool>(_First::value), _First, _Rest...>::type {
// the first true trait in _Traits, or the last trait if none are true
};

Expand Down
12 changes: 6 additions & 6 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

// GH-4845 <type_traits>: Logical operator traits with non-bool_constant arguments emit truncation warnings

#include <type_traits>
using namespace std;

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)

template <class Base, class Derived>
void test_base_derived() {
STATIC_ASSERT(is_base_of_v<Base, Derived>);
using ValueType = typename Base::value_type;
STATIC_ASSERT(is_same_v<const ValueType, decltype(Derived::type::value)>);
STATIC_ASSERT(Base::value == Derived::type::value);
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-2170500 (C1XX type trait optimization)
STATIC_ASSERT(is_same_v<const ValueType, decltype(Derived::value)>);
STATIC_ASSERT(Base::value == Derived::value);
#endif // ^^^ no workaround ^^^
}

template <short N>
using SC = integral_constant<short, N>;
template <long N>
using LC = integral_constant<long, N>;

// 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<B1, ..., BN> 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<LC<3>, conjunction<SC<2>, LC<3>>>();
test_base_derived<LC<0>, conjunction<SC<4>, LC<0>>>();
test_base_derived<SC<0>, conjunction<SC<0>, LC<5>>>();
test_base_derived<SC<0>, conjunction<SC<0>, LC<0>>>();
}

void test_disjunction() {
// N4986 [meta.logical]/10:
// The specialization disjunction<B1, ..., BN> 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<SC<6>, disjunction<SC<6>, LC<7>>>();
test_base_derived<SC<8>, disjunction<SC<8>, LC<0>>>();
test_base_derived<LC<9>, disjunction<SC<0>, LC<9>>>();
test_base_derived<LC<0>, disjunction<SC<0>, 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<B> is a Cpp17UnaryTypeTrait with a base characteristic of bool_constant<!bool(B::value)>.
test_base_derived<false_type, negation<SC<1729>>>();
test_base_derived<true_type, negation<SC<0>>>();
}