This function is yet another stdlib function that is just a simple cast, so having it appear while debugging is arguably not useful. So add it to the existing handling that always-folds some stdlib functions.
Add std::to_underlying to the set of stdlib functions that are always folded gcc/cp/ChangeLog: * cp-gimplify.cc (cp_fold): Add to_underlying. gcc/testsuite/ChangeLog: * g++.dg/opt/pr96780_cpp23.C: New. libstdc++/ChangeLog: * include/std/utility (to_underlying): Add the __always_inline__ attribute.
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index d2423fd1848..542c2f5a35e 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -3343,13 +3343,15 @@ cp_fold (tree x, fold_flags_t flags) || id_equal (DECL_NAME (callee), "addressof") /* This addressof equivalent is used heavily in libstdc++. */ || id_equal (DECL_NAME (callee), "__addressof") + || id_equal (DECL_NAME (callee), "to_underlying") || id_equal (DECL_NAME (callee), "as_const"))) { r = CALL_EXPR_ARG (x, 0); /* Check that the return and argument types are sane before folding. */ - if (INDIRECT_TYPE_P (TREE_TYPE (x)) - && INDIRECT_TYPE_P (TREE_TYPE (r))) + if (id_equal (DECL_NAME (callee), "to_underlying") + || (INDIRECT_TYPE_P (TREE_TYPE (x)) + && INDIRECT_TYPE_P (TREE_TYPE (r)))) { if (!same_type_p (TREE_TYPE (x), TREE_TYPE (r))) r = build_nop (TREE_TYPE (x), r); diff --git a/gcc/testsuite/g++.dg/opt/pr96780_cpp23.C b/gcc/testsuite/g++.dg/opt/pr96780_cpp23.C new file mode 100644 index 00000000000..a9c41b55984 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr96780_cpp23.C @@ -0,0 +1,22 @@ +// PR c++/96780 +// Verify calls to std::move/forward are folded away by the frontend. +// { dg-do compile { target c++23 } } +// { dg-additional-options "-ffold-simple-inlines -fdump-tree-gimple" } + +#include <utility> + +enum class A : char {a}; + +extern A& x; + +void f() { + auto&& x1 = std::to_underlying(x); +} + +// { dg-final { scan-tree-dump-not "= std::move" "gimple" } } +// { dg-final { scan-tree-dump-not "= std::forward" "gimple" } } +// { dg-final { scan-tree-dump-not "= std::addressof" "gimple" } } +// { dg-final { scan-tree-dump-not "= std::__addressof" "gimple" } } +// { dg-final { scan-tree-dump-not "= std::as_const" "gimple" } } +// { dg-final { scan-tree-dump-not "= std::forward_like" "gimple" } } +// { dg-final { scan-tree-dump-not "= std::to_underlying" "gimple" } } diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index 1c15c75f92b..8a85ccfd09b 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -201,7 +201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef __cpp_lib_to_underlying // C++ >= 23 /// Convert an object of enumeration type to its underlying type. template<typename _Tp> - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr underlying_type_t<_Tp> to_underlying(_Tp __value) noexcept { return static_cast<underlying_type_t<_Tp>>(__value); }