Hi! When looking into the constexpr new issues and adding is_std_construct_at function, I've noticed that with --enable-symvers=gnu-versioned-namespace all of that fails, because construct_at (but for other things forward or move etc.) aren't directly in std namespace, but in inline namespace inside of it (std::_8::{construct_at,forward,move,...}).
The following patch changes the function all of those calls use to look through inline namespaces. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2019-10-24 Jakub Jelinek <ja...@redhat.com> * typeck.c (decl_in_std_namespace_p): Return true also for decls in inline namespaces inside of std namespace. * g++.dg/cpp0x/Wpessimizing-move6.C: New test. --- gcc/cp/typeck.c.jj 2019-10-23 20:38:00.022871653 +0200 +++ gcc/cp/typeck.c 2019-10-24 11:36:14.982981481 +0200 @@ -9395,8 +9395,16 @@ maybe_warn_about_returning_address_of_lo bool decl_in_std_namespace_p (tree decl) { - return (decl != NULL_TREE - && DECL_NAMESPACE_STD_P (decl_namespace_context (decl))); + while (decl) + { + decl = decl_namespace_context (decl); + if (DECL_NAMESPACE_STD_P (decl)) + return true; + if (!DECL_NAMESPACE_INLINE_P (decl)) + return false; + decl = CP_DECL_CONTEXT (decl); + } + return false; } /* Returns true if FN, a CALL_EXPR, is a call to std::forward. */ --- gcc/testsuite/g++.dg/cpp0x/Wpessimizing-move6.C.jj 2019-10-24 11:26:17.535148996 +0200 +++ gcc/testsuite/g++.dg/cpp0x/Wpessimizing-move6.C 2019-10-24 11:27:17.359232014 +0200 @@ -0,0 +1,135 @@ +// PR c++/86981 +// { dg-do compile { target c++11 } } +// { dg-options "-Wpessimizing-move" } + +// Define std::move. +namespace std { + inline namespace _8 { } + namespace _8 { + template<typename _Tp> + struct remove_reference + { typedef _Tp type; }; + + template<typename _Tp> + struct remove_reference<_Tp&> + { typedef _Tp type; }; + + template<typename _Tp> + struct remove_reference<_Tp&&> + { typedef _Tp type; }; + + template<typename _Tp> + constexpr typename std::remove_reference<_Tp>::type&& + move(_Tp&& __t) noexcept + { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } + } +} + +struct T { + T() { } + T(const T&) { } + T(T&&) { } +}; +struct U { + U() { } + U(const U&) { } + U(U&&) { } + U(T) { } +}; + +T g; + +T +fn1 () +{ + T t; + return std::move (t); // { dg-warning "moving a local object in a return statement prevents copy elision" } +} + +T +fn2 () +{ + // Not a local variable. + return std::move (g); +} + +int +fn3 () +{ + int i = 42; + // Not a class type. + return std::move (i); +} + +T +fn4 (bool b) +{ + T t; + if (b) + throw std::move (t); + return std::move (t); // { dg-warning "moving a local object in a return statement prevents copy elision" } +} + +T +fn5 (T t) +{ + // Function parameter; std::move is redundant but not pessimizing. + return std::move (t); +} + +U +fn6 (T t, U u, bool b) +{ + if (b) + return std::move (t); + else + // Function parameter; std::move is redundant but not pessimizing. + return std::move (u); +} + +U +fn6 (bool b) +{ + T t; + U u; + if (b) + return std::move (t); + else + return std::move (u); // { dg-warning "moving a local object in a return statement prevents copy elision" } +} + +T +fn7 () +{ + static T t; + // Non-local; don't warn. + return std::move (t); +} + +T +fn8 () +{ + return T(); +} + +T +fn9 (int i) +{ + T t; + + switch (i) + { + case 1: + return std::move ((t)); // { dg-warning "moving a local object in a return statement prevents copy elision" } + case 2: + return (std::move (t)); // { dg-warning "moving a local object in a return statement prevents copy elision" } + default: + return (std::move ((t))); // { dg-warning "moving a local object in a return statement prevents copy elision" } + } +} + +int +fn10 () +{ + return std::move (42); +} Jakub