Skip to content

Commit

Permalink
Fix truncation warnings in conjunction/disjunction (#4846)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephanTLavavej authored Aug 8, 2024
1 parent a537ec5 commit 4122957
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 10 deletions.
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 @@ -365,6 +365,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 @@ -891,12 +897,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 @@ -248,6 +248,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>>>();
}

0 comments on commit 4122957

Please sign in to comment.