Bug 85270 - Trivial assignment operator not considered such
Summary: Trivial assignment operator not considered such
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid, wrong-code
Depends on:
Blocks:
 
Reported: 2018-04-06 21:36 UTC by Hubert Tong
Modified: 2023-03-15 20:49 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2023-03-14 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hubert Tong 2018-04-06 21:36:18 UTC
Trivial copy assignment operator not considered such

GCC stops considering a trivial copy assignment operator to be trivial when a non-trivial copy assignment operator is added to the class. Works with Clang; fails with GCC.

### SOURCE (<stdin>):
struct Q {
  Q &operator=(const Q &) = default;
      // defaulted on first declaration, not user-provided; trivial

  Q &operator=(Q &); // not a viable candidate at P1
};

static_assert(__is_trivially_assignable(Q &, const Q &), ""); // (P1)
    // Assertion succeeds with Clang and ICC, but fails with GCC.


### COMPILER INVOCATION:
g++ -xc++ -std=c++2a -fsyntax-only -


### ACTUAL OUTPUT:
<stdin>:8:15: error: static assertion failed


### EXPECTED OUTPUT:
(Clean compile)


### COMPILER VERSION INFO (g++ -v):
Using built-in specs.
COLLECT_GCC=/opt/wandbox/gcc-head/bin/g++
COLLECT_LTO_WRAPPER=/opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../source/configure --prefix=/opt/wandbox/gcc-head --enable-languages=c,c++ --disable-multilib --without-ppl --without-cloog-ppl --enable-checking=release --disable-nls --enable-lto LDFLAGS=-Wl,-rpath,/opt/wandbox/gcc-head/lib,-rpath,/opt/wandbox/gcc-head/lib64,-rpath,/opt/wandbox/gcc-head/lib32
Thread model: posix
gcc version 8.0.1 20180405 (experimental) (GCC)
Comment 1 Marek Polacek 2020-06-09 18:04:39 UTC
This should probably compile too:

struct S {
  S &operator=(const S &) & = default; // trivial
  S &operator=(const S &) && { return *this; } // non-trivial
};

struct R {
  S foo;
};

static_assert(__is_trivially_assignable (S &, const S &));
static_assert(__is_trivially_assignable (R &, const R &));
Comment 2 Jonathan Wakely 2023-03-14 09:50:55 UTC
This breaks std::tuple<> due to new assignment operators in C++23:

https://godbolt.org/z/9EdPrdjhW

#include <type_traits>

template <class...> struct tuple;

template <>
struct tuple<> {
    tuple() = default;
    ~tuple() = default;

    tuple(const tuple&) = default;
    tuple(tuple&&) = default;

    tuple& operator=(const tuple&) = default;
    tuple& operator=(tuple&&) = default;

    constexpr const tuple& operator=(const tuple&) const noexcept { return *this; }
    constexpr const tuple& operator=(tuple&&) const noexcept { return *this; }
};
static_assert(std::is_trivially_destructible_v<tuple<>>);
static_assert(std::is_trivially_default_constructible_v<tuple<>>);
static_assert(std::is_trivially_copy_constructible_v<tuple<>>);
static_assert(std::is_trivially_move_constructible_v<tuple<>>);
static_assert(std::is_trivially_copy_assignable_v<tuple<>>);
static_assert(std::is_trivially_move_assignable_v<tuple<>>);
static_assert(!std::is_trivially_copyable_v<tuple<>>);


<source>:23:20: error: static assertion failed
   23 | static_assert(std::is_trivially_copy_assignable_v<tuple<>>);
      |               ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:24:20: error: static assertion failed
   24 | static_assert(std::is_trivially_move_assignable_v<tuple<>>);
      |               ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 1