Bug 86646 - Special member function 'cannot be defaulted' if type alias is used
Summary: Special member function 'cannot be defaulted' if type alias is used
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 7.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2018-07-23 13:37 UTC by programmer
Modified: 2023-08-18 21:25 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-07-23 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description programmer 2018-07-23 13:37:05 UTC
GCC 7.3.0 (as well as 8.1 and 9.0 from godbolt.org) fails to compile the following code:

//---
template<int N_>
struct Foo {
  static constexpr int N = N_;// this indirection causes the error
  using Self = Foo<N>;

  Foo(const Self&) = default;
};
//---



The error message reads

> file.cpp:6:22: error: ‘Foo<N_>::Foo(const Self&)’ cannot be defaulted



I used the following command line to obtain that error message:

> g++ -Wall -Wextra -std=c++11 file.cpp
Comment 1 Jonathan Wakely 2018-07-23 16:24:47 UTC
ICC rejects it for the same reason, but I don't see any justification for that in the standard.

Clang accepts it.
Comment 2 Marek Polacek 2018-07-24 15:18:09 UTC
We reject the code because defaultable_fn_check doesn't like the copy ctor: it asks copy_fn_p whether it is a copy ctor but it doesn't think so:
12997   else if (TYPE_REF_P (arg_type)
12998            && !TYPE_REF_IS_RVALUE (arg_type)
12999            && TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)) == DECL_CONTEXT (d))
here both the main variant and the context are "struct Foo", but they compare unequal.

Will poke some more at this.
Comment 3 Andrew Pinski 2021-12-09 07:16:03 UTC
MSVC also rejects it for the same reason as GCC (and ICC). Which makes clang the one which is different than all others.
Comment 4 Arthur O'Dwyer 2023-08-18 21:25:55 UTC
I just ran into this (it's one of the examples of vendor divergence in P2953R0).
https://isocpp.org/files/papers/P2953R0.html#corner-cases

  // https://godbolt.org/z/sxv5rvn8o
  template<class>
  struct C {
    C& operator=(std::add_lvalue_reference_t<const C>) = default;
  };
  C<int> cl;

GCC 13 says:

error: 'C< <template-parameter-1-1> >& C< <template-parameter-1-1> >::operator=(std::add_lvalue_reference_t<const C< <template-parameter-1-1> > >)' cannot be defaulted
    5 |   C& operator=(std::add_lvalue_reference_t<const C>) = default;
      |                                                        ^~~~~~~

I confirm Andrew's observation that Clang is the odd one out in accepting this code (GCC, MSVC, EDG all reject). But it also seems pretty obvious that it should be accepted. Brian Bi concurs: "I couldn't figure out any reason why this shouldn't be valid."

Or again something like this:

  template<bool B>
  struct C {
    C(std::conditional_t<B, const C&, C&&>) = default;
    C(std::conditional_t<B, C&&, const C&>);
  };
  static_assert(std::is_trivially_copy_constructible_v<C<true>>);
  static_assert(std::is_trivially_move_constructible_v<C<false>>);

GCC+EDG+MSVC reject; Clang accepts; and I think Clang is the conforming one.

A related situation is

  // https://godbolt.org/z/1bhEx1Gr1
  template<class... Ts>
  struct C {
    template<class T> using A = const C&;
    C(A<Ts>...) = default;
      // this is a default ctor or a copy ctor, depending on sizeof...(Ts)
  };
  static_assert(std::is_trivially_constructible_v<C<>>);
  static_assert(std::is_trivially_copy_constructible_v<C<int>>);

GCC rejects; Clang+EDG+MSVC accept; and I think Clang+EDG+MSVC are conforming.