https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431

--- Comment #19 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Author: redi
Date: Fri Apr  5 16:56:09 2019
New Revision: 270170

URL: https://gcc.gnu.org/viewcvs?rev=270170&root=gcc&view=rev
Log:
PR libstdc++/87431 re-adjust never-valueless optimizations

Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.

Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.

As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.

        PR libstdc++/87431 (again)
        * include/bits/basic_string.h (__variant::_Never_valueless_alt):
        Define partial specialization for basic_string.
        * include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
        shared_ptr and weak_ptr.
        * include/bits/std_function.h (_Never_valueless_alt): Likewise for
        function.
        * include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
        vector.
        * include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
        unique_ptr.
        * include/debug/vector (_Never_valueless_alt): Likewise for debug
        vector.
        * include/std/any (_Never_valueless_alt): Define explicit
        specialization for any.
        * include/std/variant (_Never_valueless_alt): Define primary template.
        (__never_valueless): Use _Never_valueless_alt instead of
        is_trivially_copyable.
        (variant::emplace<N>(Args&&...)): Add special case for non-throwing
        initializations to avoid try-catch overhead. Add special case for
        scalars produced by potentially-throwing conversions. Use
        _Never_valueless_alt instead of is_trivially_copyable for the
        remaining strong exception-safety cases.
        (variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
        * testsuite/20_util/variant/87431.cc: Run both test functions.
        * testsuite/20_util/variant/exception_safety.cc: New test.
        * testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
        so the variant becomes valueless.

Added:
    trunk/libstdc++-v3/testsuite/20_util/variant/exception_safety.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/bits/basic_string.h
    trunk/libstdc++-v3/include/bits/shared_ptr.h
    trunk/libstdc++-v3/include/bits/std_function.h
    trunk/libstdc++-v3/include/bits/stl_vector.h
    trunk/libstdc++-v3/include/bits/unique_ptr.h
    trunk/libstdc++-v3/include/debug/vector
    trunk/libstdc++-v3/include/std/any
    trunk/libstdc++-v3/include/std/variant
    trunk/libstdc++-v3/testsuite/20_util/variant/87431.cc
    trunk/libstdc++-v3/testsuite/20_util/variant/run.cc

Reply via email to