diff options
author | Luc Grosheintz <luc.grosheintz@gmail.com> | 2025-09-04 14:20:28 +0200 |
---|---|---|
committer | Tomasz Kamiński <tkaminsk@redhat.com> | 2025-09-08 09:38:53 +0200 |
commit | c440b585ba374b6348ef223e4891a717a1f6660c (patch) | |
tree | 3ad8da30efbb30d17276f54ca2d95fc21ddb27bb /libstdc++-v3/testsuite | |
parent | 565d9a3617fcc167f190e04445a1d7952b4d9bba (diff) | |
download | gcc-c440b585ba374b6348ef223e4891a717a1f6660c.zip gcc-c440b585ba374b6348ef223e4891a717a1f6660c.tar.gz gcc-c440b585ba374b6348ef223e4891a717a1f6660c.tar.bz2 |
libstdc++: Implement constant_wrapper, cw from P2781R9.
This is a partial implementation of P2781R9. It adds std::cw and
std::constant_wrapper, but doesn't modify __integral_constant_like for
span/mdspan.
libstdc++-v3/ChangeLog:
* include/bits/version.def (constant_wrapper): Add.
* include/bits/version.h: Regenerate.
* include/std/type_traits (_CwFixedValue): New class.
(_IndexSequence): New struct.
(_BuildIndexSequence): New struct.
(_ConstExprParam): New concept.
(_CwOperators): New struct.
(constant_wrapper): New struct.
(cw): New global constant.
* src/c++23/std.cc.in (constant_wrapper): Add.
(cw): Add.
* testsuite/20_util/constant_wrapper/adl.cc: New test.
* testsuite/20_util/constant_wrapper/ex.cc: New test.
* testsuite/20_util/constant_wrapper/generic.cc: New test.
* testsuite/20_util/constant_wrapper/instantiate.cc: New test.
* testsuite/20_util/constant_wrapper/op_comma_neg.cc: New test.
* testsuite/20_util/constant_wrapper/version.cc: New test.
Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Co-authored-by: Tomasz Kamiński <tkaminsk@redhat.com>
Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
Diffstat (limited to 'libstdc++-v3/testsuite')
7 files changed, 1191 insertions, 0 deletions
diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/adl.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/adl.cc new file mode 100644 index 0000000..3cdc09c --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/adl.cc @@ -0,0 +1,86 @@ +// { dg-do compile { target c++26 } } +#include <type_traits> +#include <concepts> + +#include <testsuite_hooks.h> + +namespace adl { + +struct Friend +{}; + +constexpr +int operator+(Friend, int x) +{ return x; }; + +template<typename T> + struct TemplFriend + { }; + +template<typename T> + constexpr + // templated, we cannot deduce T from cw<Friend<int>> + int operator+(TemplFriend<T>, int x) + { return x; }; + + +struct HiddenFriend +{ + constexpr friend + int operator+(HiddenFriend, int x) + { return x; } +}; + +template<typename T> + struct TemplHiddenFriend + { + constexpr friend + // note that this not not template itself + int operator+(TemplHiddenFriend, int x) + { return x; } + }; +} + +template<typename T> + concept supportMixedObj = requires + { + { std::cw<T{}> + 1 } -> std::same_as<int>; + }; + +template<typename T> + concept supportMixedInt = requires(T t) + { + { t + std::cw<1> } -> std::same_as<int>; + }; + +static_assert(supportMixedObj<adl::Friend>); +static_assert(supportMixedInt<adl::Friend>); +static_assert(!supportMixedObj<adl::TemplFriend<int>>); +static_assert(supportMixedInt<adl::TemplFriend<int>>); + +static_assert(supportMixedObj<adl::HiddenFriend>); +static_assert(supportMixedInt<adl::HiddenFriend>); +static_assert(supportMixedObj<adl::TemplHiddenFriend<int>>); +static_assert(supportMixedInt<adl::TemplHiddenFriend<int>>); + +struct Member +{ + constexpr + // conversion for the first argument is not allowed + int operator+(int x) const + { return x; } +}; + +static_assert(!supportMixedObj<Member>); +static_assert(supportMixedInt<Member>); + +struct ExplicitThisMember +{ + constexpr + // conversion for the first argument is not allowed + int operator+(this ExplicitThisMember, int x) + { return x; } +}; + +static_assert(!supportMixedObj<ExplicitThisMember>); +static_assert(supportMixedInt<ExplicitThisMember>); diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/ex.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/ex.cc new file mode 100644 index 0000000..a4d967b --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/ex.cc @@ -0,0 +1,39 @@ +// { dg-do compile { target c++26 } } +#include <type_traits> +#include <iostream> + +#include <testsuite_hooks.h> + +constexpr auto +initial_phase(auto quantity_1, auto quantity_2) +{ return quantity_1 + quantity_2; } + +constexpr auto +middle_phase(auto tbd) +{ return tbd; } + +constexpr void +final_phase(auto gathered, auto available) +{ + if constexpr (gathered == available) + std::cout << "Profit!\n"; +} + +void +impeccable_underground_planning() +{ + auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>)); + static_assert(gathered_quantity == 55); + auto all_available = std::cw<55>; + final_phase(gathered_quantity, all_available); +} + +void +deeply_flawed_underground_planning() +{ + constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13)); + constexpr auto all_available = 55; + final_phase(gathered_quantity, all_available); // { dg-error "required from here" } +} + +// { dg-prune-output "'gathered' is not a constant expression" } diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc new file mode 100644 index 0000000..f632f8e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc @@ -0,0 +1,391 @@ +// { dg-do run { target c++26 } } +#include <type_traits> +#include <utility> +#include <string_view> + +#include <testsuite_hooks.h> + +constexpr void +check_same(auto actual, auto expected) +{ + VERIFY(actual == expected); + static_assert(std::same_as<decltype(actual), decltype(expected)>); +}; + + +constexpr void +test_c_arrays() +{ + constexpr double x[] = {1.1, 2.2, 3.3}; + auto cx = std::cw<x>; + auto access = [](auto x, size_t i) + { return x[i]; }; + + check_same(access(std::cw<x>, 0), x[0]); + check_same(access(std::cw<x>, 1), x[1]); + check_same(access(std::cw<x>, 2), x[2]); + + check_same(cx[std::cw<0>], std::cw<x[0]>); + check_same(cx[std::cw<1>], std::cw<x[1]>); + check_same(cx[std::cw<2>], std::cw<x[2]>); +} + +constexpr size_t +deduce_cstr_size(auto str) +{ + size_t sz = 0; + while(str[sz++] != '\0') { } + return sz; +} + +constexpr void +test_string_literals() +{ + auto foo = std::cw<"foo">; + constexpr const typename decltype(foo)::value_type & cstr = foo; + constexpr size_t N = std::size(cstr); + constexpr auto foo_view = std::string_view(cstr, N-1); + + constexpr const char (&cstr1)[deduce_cstr_size(foo)] = foo; + constexpr size_t N1 = std::size(cstr); + + static_assert(static_cast<char const*>(cstr) == + static_cast<char const*>(cstr1)); + static_assert(N1 == N); + + static_assert(foo[0] == 'f'); + static_assert(foo[1] == 'o'); + static_assert(foo[2] == 'o'); + static_assert(foo[3] == '\0'); + static_assert(static_cast<char const *>(foo) == foo_view); +} + +constexpr bool +convert_constexpr(auto c) +{ + if constexpr (int(c) > 0) + return true; + return false; +} + +constexpr void +test_converted_constexpr() +{ + VERIFY(!convert_constexpr(std::cw<-1>)); + VERIFY(convert_constexpr(std::cw<1>)); +} + +constexpr void +test_ints() +{ + std::constant_wrapper<2> two; + std::constant_wrapper<3> three; + std::constant_wrapper<5> five; + + VERIFY(two + 3 == 5); + static_assert(std::same_as<decltype(two + 3), int>); + + VERIFY(two + three == 5); + VERIFY(two + three == five); + static_assert(std::same_as<decltype(two + three), std::constant_wrapper<5>>); + + VERIFY(two == std::cw<2>); + VERIFY(two + 3 == std::cw<5>); +} + +constexpr int +add(int i, int j) +{ return i + j; } + +struct Add +{ + constexpr int + operator()(int i, int j) const noexcept + { return i + j; } +}; + +constexpr void +test_function_object() +{ + auto check = [](auto cfo) + { + auto ci = std::cw<2>; + auto cj = std::cw<3>; + + VERIFY(cfo(ci, cj) == 5); + static_assert(std::same_as<decltype(cfo(ci, cj)), std::constant_wrapper<5>>); + + static_assert(std::invocable<decltype(cfo), decltype(ci), decltype(cj)>); + static_assert(!std::invocable<decltype(cfo), int, decltype(cj)>); + static_assert(!std::invocable<decltype(cfo), int, int>); + }; + + check(std::cw<Add{}>); + check(std::cw<[](int i, int j){ return i + j; }>); + check(std::cw<[](auto i, auto j){ return i + j; }>); +} + +constexpr void +test_function_pointer() +{ + auto cptr = std::cw<add>; + auto ci = std::cw<2>; + auto cj = std::cw<3>; + + VERIFY(cptr(ci, cj) == 5); + static_assert(std::same_as<decltype(cptr(ci, cj)), std::constant_wrapper<5>>); + + VERIFY(cptr(2, cj) == 5); + static_assert(std::same_as<decltype(cptr(2, cj)), int>); + + VERIFY(cptr(2, 3) == 5); + static_assert(std::same_as<decltype(cptr(2, 3)), int>); +} + +struct Indexable1 +{ + constexpr int + operator[](int i, int j) const noexcept + { return i*j; } +}; + +template<typename Obj, typename... Args> + concept indexable = requires (Obj obj, Args... args) + { + obj[args...]; + }; + +constexpr void +test_indexable1() +{ + auto cind = std::cw<Indexable1{}>; + auto ci = std::cw<2>; + auto cj = std::cw<3>; + VERIFY(cind[ci, cj] == ci*cj); + static_assert(std::same_as<decltype(cind[ci, cj]), std::constant_wrapper<6>>); + + static_assert(indexable<decltype(cind), decltype(ci), decltype(cj)>); + static_assert(!indexable<decltype(cind), int, decltype(cj)>); + static_assert(!indexable<decltype(cind), int, int>); +} + +struct Indexable2 +{ + template<typename I, typename J> + constexpr int + operator[](I i, J j) const noexcept + { return i*j; } +}; + +constexpr void +test_indexable2() +{ + auto cind = std::cw<Indexable2{}>; + auto ci = std::cw<2>; + auto cj = std::cw<3>; + VERIFY(cind[ci, cj] == ci*cj); + static_assert(std::same_as<decltype(cind[ci, cj]), std::constant_wrapper<6>>); + + static_assert(indexable<decltype(cind), decltype(ci), decltype(cj)>); + static_assert(!indexable<decltype(cind), int, decltype(cj)>); + static_assert(!indexable<decltype(cind), int, int>); +} + +struct Indexable3 +{ + template<typename... Is> + constexpr int + operator[](Is... i) const noexcept + { return (1 * ... * i); } +}; + +constexpr void +test_indexable3() +{ + auto cind = std::cw<Indexable3{}>; + auto ci = std::cw<2>; + auto cj = std::cw<3>; + + check_same(cind[], std::cw<1>); + check_same(cind[ci], std::cw<2>); + check_same(cind[ci, cj], std::cw<2*3>); +} + +struct Divide +{ + int value; + + constexpr int + divide(int div) const + { return value / div; } + +}; + +constexpr void +test_member_pointer() +{ + constexpr int nom = 42; + constexpr int denom = 3; + + auto cvalue = std::cw<&Divide::value>; + auto cdiv = std::cw<&Divide::divide>; + auto co = std::cw<Divide{nom}>; + + check_same((&co)->*cvalue, std::cw<nom>); + check_same((&co)->*(&Divide::value), nom); + check_same(&(co.value)->*cvalue, nom); + + auto expect_unwrapped = nom / denom; + check_same(((&co)->*(&Divide::divide))(denom), expect_unwrapped); + check_same((&(co.value)->*cdiv)(denom), expect_unwrapped); + check_same(((&decltype(co)::value)->*cdiv)(denom), expect_unwrapped); +} + +constexpr void +test_pseudo_mutator() +{ + auto ci = std::cw<3>; + auto cmmi = --ci; + VERIFY(ci.value == 3); + VERIFY(cmmi.value == 2); + + auto cimm = ci--; + VERIFY(ci.value == 3); + VERIFY(cimm.value == 3); +} + +struct Truthy +{ + constexpr operator bool() const + { return true; } +}; + +template<typename Lhs, typename Rhs> + concept has_op_and = requires (Lhs lhs, Rhs rhs) + { + lhs && rhs; + }; + +constexpr void +test_logic() +{ + auto ctrue = std::cw<true>; + auto cfalse = std::cw<false>; + auto truthy = Truthy{}; + + auto check_and = [](auto lhs, auto rhs) + { + static_assert(lhs && rhs); + static_assert(std::same_as<decltype(lhs && rhs), bool>); + }; + + auto check_or = [](auto lhs, auto rhs) + { + static_assert(lhs || rhs); + static_assert(std::same_as<decltype(lhs || rhs), bool>); + }; + + check_and(ctrue, ctrue); + check_or(ctrue, cfalse); + check_and((std::cw<0> < std::cw<1>), (std::cw<1> < std::cw<5>)); + check_or((std::cw<0> < std::cw<1>), (std::cw<1> < std::cw<5>)); + + auto ctruthy = std::cw<Truthy{}>; + static_assert(has_op_and<decltype(truthy), bool>); + static_assert(!has_op_and<decltype(ctruthy), decltype(ctrue)>); + static_assert(!has_op_and<decltype(ctruthy), bool>); +} + +struct ThreeWayComp +{ + friend + constexpr std::strong_ordering + operator<=>(ThreeWayComp lhs, ThreeWayComp rhs) + { return lhs.value <=> rhs.value; } + + int value; +}; + +constexpr void +test_three_way() +{ + auto ctrue = std::cw<true>; + auto cfalse = std::cw<false>; + + check_same(std::cw<ThreeWayComp{0}> < std::cw<ThreeWayComp{1}>, ctrue); + check_same(std::cw<ThreeWayComp{2}> > std::cw<ThreeWayComp{1}>, ctrue); + check_same(std::cw<ThreeWayComp{2}> >= std::cw<ThreeWayComp{1}>, ctrue); + check_same(std::cw<ThreeWayComp{0}> <= std::cw<ThreeWayComp{1}>, ctrue); + check_same(std::cw<ThreeWayComp{0}> >= std::cw<ThreeWayComp{1}>, cfalse); + + check_same(std::cw<ThreeWayComp{0}> < ThreeWayComp{1}, true); + check_same(ThreeWayComp{2} > std::cw<ThreeWayComp{1}>, true); +} + +struct EqualityComp +{ + friend + constexpr bool + operator==(EqualityComp lhs, EqualityComp rhs) + { return lhs.value == rhs.value; } + + int value; +}; + +constexpr void +test_equality() +{ + auto ctrue = std::cw<true>; + check_same(std::cw<EqualityComp{1}> == std::cw<EqualityComp{1}>, ctrue); + check_same(std::cw<EqualityComp{0}> != std::cw<EqualityComp{1}>, ctrue); + + check_same(std::cw<EqualityComp{1}> == EqualityComp{1}, true); + check_same(EqualityComp{0} != std::cw<EqualityComp{1}>, true); +} + +struct ConstAssignable +{ + int value; + + constexpr ConstAssignable + operator=(int rhs) const + { return ConstAssignable{rhs}; } + + friend constexpr bool + operator==(const ConstAssignable& lhs, const ConstAssignable& rhs) + { return lhs.value == rhs.value; } +}; + +constexpr void +test_assignment() +{ + check_same(std::cw<ConstAssignable{3}> = std::cw<2>, + std::cw<ConstAssignable{2}>); +} + + +constexpr bool +test_all() +{ + test_c_arrays(); + test_ints(); + test_function_object(); + test_function_pointer(); + test_indexable1(); + test_indexable2(); + test_indexable3(); + test_member_pointer(); + test_pseudo_mutator(); + test_logic(); + test_three_way(); + test_equality(); + return true; +} + +int +main() +{ + test_all(); + static_assert(test_all()); + return 0; +} diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc new file mode 100644 index 0000000..4f12325 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc @@ -0,0 +1,575 @@ +// { dg-do run { target c++26 } } +#include <type_traits> +#include <utility> + +#include <testsuite_hooks.h> + +namespace free_ops +{ + template<int OpId> + struct UnaryOps + { + friend constexpr int + operator+(UnaryOps) noexcept requires (OpId == 0) + { return OpId; } + + friend constexpr int + operator-(UnaryOps) noexcept requires (OpId == 1) + { return OpId; } + + friend constexpr int + operator~(UnaryOps) noexcept requires (OpId == 2) + { return OpId; } + + friend constexpr int + operator!(UnaryOps) noexcept requires (OpId == 3) + { return OpId; } + + friend constexpr int + operator&(UnaryOps) noexcept requires (OpId == 4) + { return OpId; } + + friend constexpr int + operator*(UnaryOps) noexcept requires (OpId == 5) + { return OpId; } + + friend constexpr int + operator++(UnaryOps) noexcept requires (OpId == 6) + { return OpId; } + + friend constexpr int + operator++(UnaryOps, int) noexcept requires (OpId == 7) + { return OpId; } + + friend constexpr int + operator--(UnaryOps) noexcept requires (OpId == 8) + { return OpId; } + + friend constexpr int + operator--(UnaryOps, int) noexcept requires (OpId == 9) + { return OpId; } + }; +} + +namespace member_ops +{ + template<int OpId> + struct UnaryOps + { + constexpr int + operator+() const noexcept requires (OpId == 0) + { return OpId; } + + constexpr int + operator-() const noexcept requires (OpId == 1) + { return OpId; } + + constexpr int + operator~() const noexcept requires (OpId == 2) + { return OpId; } + + constexpr int + operator!() const noexcept requires (OpId == 3) + { return OpId; } + + constexpr int + operator&() const noexcept requires (OpId == 4) + { return OpId; } + + constexpr int + operator*() const noexcept requires (OpId == 5) + { return OpId; } + + constexpr int + operator++() const noexcept requires (OpId == 6) + { return OpId; } + + constexpr int + operator++(int) const noexcept requires (OpId == 7) + { return OpId; } + + constexpr int + operator--() const noexcept requires (OpId == 8) + { return OpId; } + + constexpr int + operator--(int) const noexcept requires (OpId == 9) + { return OpId; } + }; +} + +constexpr size_t n_unary_ops = 10; + +template<template<int> typename Ops, int OpId> + constexpr void + test_unary_operator() + { + auto x = std::cw<Ops<OpId>{}>; + + auto check = [](auto c) + { + VERIFY(c == OpId); + static_assert(std::same_as<decltype(c), std::constant_wrapper<OpId>>); + }; + + if constexpr (OpId == 0) + check(+x); + if constexpr (OpId == 1) + check(-x); + if constexpr (OpId == 2) + check(~x); + if constexpr (OpId == 3) + check(!x); + if constexpr (OpId == 4) + check(&x); + if constexpr (OpId == 5) + check(*x); + if constexpr (OpId == 6) + check(++x); + if constexpr (OpId == 7) + check(x++); + if constexpr (OpId == 8) + check(--x); + if constexpr (OpId == 9) + check(x--); + + static_assert(n_unary_ops == 10); + } + +constexpr void +test_unary_operators_all() +{ + auto run = []<size_t... Idx>(std::integer_sequence<size_t, Idx...>) + { + (test_unary_operator<free_ops::UnaryOps, Idx>(), ...); + (test_unary_operator<member_ops::UnaryOps, Idx>(), ...); + }; + run(std::make_index_sequence<n_unary_ops>()); +} + +namespace free_ops +{ + template<int OpId> + struct BinaryOps + { + friend constexpr int + operator+(BinaryOps, BinaryOps) noexcept requires (OpId == 0) + { return OpId; } + + friend constexpr int + operator-(BinaryOps, BinaryOps) noexcept requires (OpId == 1) + { return OpId; } + + friend constexpr int + operator*(BinaryOps, BinaryOps) noexcept requires (OpId == 2) + { return OpId; } + + friend constexpr int + operator/(BinaryOps, BinaryOps) noexcept requires (OpId == 3) + { return OpId; } + + friend constexpr int + operator%(BinaryOps, BinaryOps) noexcept requires (OpId == 4) + { return OpId; } + + friend constexpr int + operator<<(BinaryOps, BinaryOps) noexcept requires (OpId == 5) + { return OpId; } + + friend constexpr int + operator>>(BinaryOps, BinaryOps) noexcept requires (OpId == 6) + { return OpId; } + + friend constexpr int + operator&(BinaryOps, BinaryOps) noexcept requires (OpId == 7) + { return OpId; } + + friend constexpr int + operator|(BinaryOps, BinaryOps) noexcept requires (OpId == 8) + { return OpId; } + + friend constexpr int + operator^(BinaryOps, BinaryOps) noexcept requires (OpId == 9) + { return OpId; } + + friend constexpr int + operator&&(BinaryOps, BinaryOps) noexcept requires (OpId == 10) + { return OpId; } + + friend constexpr int + operator||(BinaryOps, BinaryOps) noexcept requires (OpId == 11) + { return OpId; } + + friend constexpr int + operator<=>(BinaryOps, BinaryOps) noexcept requires (OpId == 12) + { return OpId; } + + friend constexpr int + operator<(BinaryOps, BinaryOps) noexcept requires (OpId == 13) + { return OpId; } + + friend constexpr int + operator<=(BinaryOps, BinaryOps) noexcept requires (OpId == 14) + { return OpId; } + + friend constexpr int + operator==(BinaryOps, BinaryOps) noexcept requires (OpId == 15) + { return OpId; } + + friend constexpr int + operator!=(BinaryOps, BinaryOps) noexcept requires (OpId == 16) + { return OpId; } + + friend constexpr int + operator>(BinaryOps, BinaryOps) noexcept requires (OpId == 17) + { return OpId; } + + friend constexpr int + operator>=(BinaryOps, BinaryOps) noexcept requires (OpId == 18) + { return OpId; } + + friend constexpr int + operator+=(BinaryOps, BinaryOps) noexcept requires (OpId == 19) + { return OpId; } + + friend constexpr int + operator-=(BinaryOps, BinaryOps) noexcept requires (OpId == 20) + { return OpId; } + + friend constexpr int + operator*=(BinaryOps, BinaryOps) noexcept requires (OpId == 21) + { return OpId; } + + friend constexpr int + operator/=(BinaryOps, BinaryOps) noexcept requires (OpId == 22) + { return OpId; } + + friend constexpr int + operator%=(BinaryOps, BinaryOps) noexcept requires (OpId == 23) + { return OpId; } + + friend constexpr int + operator&=(BinaryOps, BinaryOps) noexcept requires (OpId == 24) + { return OpId; } + + friend constexpr int + operator|=(BinaryOps, BinaryOps) noexcept requires (OpId == 25) + { return OpId; } + friend constexpr int + + operator^=(BinaryOps, BinaryOps) noexcept requires (OpId == 26) + { return OpId; } + + friend constexpr int + operator<<=(BinaryOps, BinaryOps) noexcept requires (OpId == 27) + { return OpId; } + + friend constexpr int + operator>>=(BinaryOps, BinaryOps) noexcept requires (OpId == 28) + { return OpId; } + }; +} + +namespace member_ops +{ + template<int OpId> + struct BinaryOps + { + constexpr int + operator+(BinaryOps) const noexcept requires (OpId == 0) + { return OpId; } + + constexpr int + operator-(BinaryOps) const noexcept requires (OpId == 1) + { return OpId; } + + constexpr int + operator*(BinaryOps) const noexcept requires (OpId == 2) + { return OpId; } + + constexpr int + operator/(BinaryOps) const noexcept requires (OpId == 3) + { return OpId; } + + constexpr int + operator%(BinaryOps) const noexcept requires (OpId == 4) + { return OpId; } + + constexpr int + operator<<(BinaryOps) const noexcept requires (OpId == 5) + { return OpId; } + + constexpr int + operator>>(BinaryOps) const noexcept requires (OpId == 6) + { return OpId; } + + constexpr int + operator&(BinaryOps) const noexcept requires (OpId == 7) + { return OpId; } + + constexpr int + operator|(BinaryOps) const noexcept requires (OpId == 8) + { return OpId; } + + constexpr int + operator^(BinaryOps) const noexcept requires (OpId == 9) + { return OpId; } + + constexpr int + operator&&(BinaryOps) const noexcept requires (OpId == 10) + { return OpId; } + + constexpr int + operator||(BinaryOps) const noexcept requires (OpId == 11) + { return OpId; } + + constexpr int + operator<=>(BinaryOps) const noexcept requires (OpId == 12) + { return OpId; } + + constexpr int + operator<(BinaryOps) const noexcept requires (OpId == 13) + { return OpId; } + + constexpr int + operator<=(BinaryOps) const noexcept requires (OpId == 14) + { return OpId; } + + constexpr int + operator==(BinaryOps) const noexcept requires (OpId == 15) + { return OpId; } + + constexpr int + operator!=(BinaryOps) const noexcept requires (OpId == 16) + { return OpId; } + + constexpr int + operator>(BinaryOps) const noexcept requires (OpId == 17) + { return OpId; } + + constexpr int + operator>=(BinaryOps) const noexcept requires (OpId == 18) + { return OpId; } + + constexpr int + operator+=(BinaryOps) const noexcept requires (OpId == 19) + { return OpId; } + + constexpr int + operator-=(BinaryOps) const noexcept requires (OpId == 20) + { return OpId; } + + constexpr int + operator*=(BinaryOps) const noexcept requires (OpId == 21) + { return OpId; } + + constexpr int + operator/=(BinaryOps) const noexcept requires (OpId == 22) + { return OpId; } + + constexpr int + operator%=(BinaryOps) const noexcept requires (OpId == 23) + { return OpId; } + + constexpr int + operator&=(BinaryOps) const noexcept requires (OpId == 24) + { return OpId; } + + constexpr int + operator|=(BinaryOps) const noexcept requires (OpId == 25) + { return OpId; } + + constexpr int + operator^=(BinaryOps) const noexcept requires (OpId == 26) + { return OpId; } + + constexpr int + operator<<=(BinaryOps) const noexcept requires (OpId == 27) + { return OpId; } + + constexpr int + operator>>=(BinaryOps) const noexcept requires (OpId == 28) + { return OpId; } + }; +} + +constexpr size_t n_binary_ops = 29; + +template<template<int> typename Ops, int OpId> + constexpr void + test_binary_operator() + { + auto cx = std::cw<Ops<OpId>{}>; + auto cy = std::cw<Ops<OpId>{}>; + + auto check = [](auto c) + { + VERIFY(c == OpId); + static_assert(std::same_as<decltype(c), std::constant_wrapper<OpId>>); + }; + + if constexpr (OpId == 0) + check(cx + cy); + if constexpr (OpId == 1) + check(cx - cy); + if constexpr (OpId == 2) + check(cx * cy); + if constexpr (OpId == 3) + check(cx / cy); + if constexpr (OpId == 4) + check(cx % cy); + if constexpr (OpId == 5) + check(cx << cy); + if constexpr (OpId == 6) + check(cx >> cy); + if constexpr (OpId == 7) + check(cx & cy); + if constexpr (OpId == 8) + check(cx | cy); + if constexpr (OpId == 10) + check(cx && cy); + if constexpr (OpId == 11) + check(cx || cy); + if constexpr (OpId == 12) + check(cx <=> cy); + if constexpr (OpId == 13) + check(cx < cy); + if constexpr (OpId == 14) + check(cx <= cy); + if constexpr (OpId == 15) + check(cx == cy); + if constexpr (OpId == 16) + check(cx != cy); + if constexpr (OpId == 17) + check(cx > cy); + if constexpr (OpId == 18) + check(cx >= cy); + if constexpr (OpId == 19) + check(cx += cy); + if constexpr (OpId == 20) + check(cx -= cy); + if constexpr (OpId == 21) + check(cx *= cy); + if constexpr (OpId == 22) + check(cx /= cy); + if constexpr (OpId == 23) + check(cx %= cy); + if constexpr (OpId == 24) + check(cx &= cy); + if constexpr (OpId == 25) + check(cx |= cy); + if constexpr (OpId == 26) + check(cx ^= cy); + if constexpr (OpId == 27) + check(cx <<= cy); + if constexpr (OpId == 28) + check(cx >>= cy); + static_assert(n_binary_ops == 29); + } + +template<template<int> typename Ops, int OpId> + constexpr void + test_mixed_binary_operators() + { + constexpr auto x = Ops<OpId>{}; + auto cx = std::cw<x>; + constexpr auto y = Ops<OpId>{}; + auto cy = std::cw<y>; + + auto check = [](auto vc, auto cv) + { + auto impl = [](auto c) + { + VERIFY(c == OpId); + static_assert(std::same_as<decltype(c), int>); + }; + + impl(vc); + impl(cv); + }; + + if constexpr (OpId == 0) + check(x + cy, cx + y); + if constexpr (OpId == 1) + check(x - cy, cx - y); + if constexpr (OpId == 2) + check(x * cy, cx * y); + if constexpr (OpId == 3) + check(x / cy, cx / y); + if constexpr (OpId == 4) + check(x % cy, cx % y); + if constexpr (OpId == 5) + check(x << cy, cx << y); + if constexpr (OpId == 6) + check(x >> cy, cx >> y); + if constexpr (OpId == 7) + check(x & cy, cx & y); + if constexpr (OpId == 8) + check(x | cy, cx | y); + if constexpr (OpId == 10) + check(x && cy, cx && y); + if constexpr (OpId == 11) + check(x || cy, cx || y); + if constexpr (OpId == 12) + check(x <=> cy, cx <=> y); + if constexpr (OpId == 13) + check(x < cy, cx < y); + if constexpr (OpId == 14) + check(x <= cy, cx <= y); + if constexpr (OpId == 15) + check(x == cy, cx == y); + if constexpr (OpId == 16) + check(x != cy, cx != y); + if constexpr (OpId == 17) + check(x > cy, cx > y); + if constexpr (OpId == 18) + check(x >= cy, cx >= y); + if constexpr (OpId == 19) + check(x += cy, cx += y); + if constexpr (OpId == 20) + check(x -= cy, cx -= y); + if constexpr (OpId == 21) + check(x *= cy, cx *= y); + if constexpr (OpId == 22) + check(x /= cy, cx /= y); + if constexpr (OpId == 23) + check(x %= cy, cx %= y); + if constexpr (OpId == 24) + check(x &= cy, cx &= y); + if constexpr (OpId == 25) + check(x |= cy, cx |= y); + if constexpr (OpId == 26) + check(x ^= cy, cx ^= y); + if constexpr (OpId == 27) + check(x <<= cy, cx <<= y); + if constexpr (OpId == 28) + check(x >>= cy, cx >>= y); + static_assert(n_binary_ops == 29); + } + +constexpr void +test_binary_operators_all() +{ + auto run = []<size_t... Idx>(std::integer_sequence<size_t, Idx...>) + { + (test_binary_operator<free_ops::BinaryOps, Idx>(), ...); + (test_mixed_binary_operators<free_ops::BinaryOps, Idx>(), ...); + (test_binary_operator<member_ops::BinaryOps, Idx>(), ...); + }; + run(std::make_index_sequence<n_binary_ops>()); +} + +constexpr bool +test_all() +{ + test_unary_operators_all(); + test_binary_operators_all(); + return true; +} + +int +main() +{ + test_all(); + return 0; +} diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/op_comma_neg.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/op_comma_neg.cc new file mode 100644 index 0000000..4384e92 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/op_comma_neg.cc @@ -0,0 +1,14 @@ +// { dg-do compile { target c++26 } } +#include <type_traits> + +constexpr void +test_comma_same_types() +{ + (std::cw<1>, std::cw<2>); // { dg-error "use of deleted function" } +} + +constexpr void +test_comma_different_types() +{ + (std::cw<1>, std::cw<2.0>); // { dg-error "use of deleted function" } +} diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc new file mode 100644 index 0000000..3c3cfaf --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc @@ -0,0 +1,75 @@ +// { dg-do run { target c++26 } } +#include <type_traits> +#include <concepts> + +#include <testsuite_hooks.h> + +template<typename Type, Type Value> + struct ConstWrapper + { + constexpr static Type value = Value; + }; + +constexpr void +check_same(auto actual, auto expected) +{ + VERIFY(actual == expected); + static_assert(std::same_as<decltype(actual), decltype(expected)>); +} + +constexpr void +test_mix_integer_constant() +{ + auto i4 = std::integral_constant<int, 4>{}; + auto c3 = std::cw<3>; + auto w2 = ConstWrapper<int, 2>{}; + + check_same(i4 + c3, std::cw<7>); + check_same(c3 + i4, std::cw<7>); + check_same(c3 + w2, std::cw<5>); + check_same(w2 + c3, std::cw<5>); +} + +constexpr void +test_array() +{ + constexpr double x[] = {1.1, 2.2, 3.3}; + auto cx = std::cw<x>; + auto i2 = std::integral_constant<int, 2>{}; + auto w2 = ConstWrapper<int, 2>{}; + + check_same(x[i2], x[2]); + check_same(cx[i2], std::cw<x[2]>); + check_same(cx[w2], std::cw<x[2]>); +} + +constexpr void +test_function_object() +{ + auto cadd = std::cw<[](int i, int j) { return i + j; }>; + auto i4 = std::integral_constant<int, 4>{}; + auto c3 = std::cw<3>; + auto w2 = ConstWrapper<int, 2>{}; + + check_same(cadd(i4, c3), std::cw<7>); + check_same(cadd(c3, i4), std::cw<7>); + check_same(cadd(w2, c3), std::cw<5>); + check_same(cadd(c3, w2), std::cw<5>); +} + +constexpr bool +test_all() +{ + test_mix_integer_constant(); + test_array(); + test_function_object(); + return true; +} + +int +main() +{ + test_all(); + static_assert(test_all()); + return 0; +} diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/version.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/version.cc new file mode 100644 index 0000000..4fee615 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/version.cc @@ -0,0 +1,11 @@ +// { dg-do preprocess { target c++26 } } +// { dg-add-options no_pch } + +#include <type_traits> + +#ifndef __cpp_lib_constant_wrapper +#error "Feature test macro __cpp_lib_constant_wrapper is missing for <type_traits>" +#if __cpp_lib_constant_wrapper < 202506L +#error "Feature test macro __cpp_lib_constant_wrapper has the wrong value" +#endif +#endif |