Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

bogus -Wmissing-braces for CTAD deduced aggregate with inherited base #45745

Open Quuxplusone opened 4 years ago

Quuxplusone commented 4 years ago
Bugzilla Link PR46776
Status NEW
Importance P enhancement
Reported by Will Wray (wjwray@gmail.com)
Reported on 2020-07-19 12:22:01 -0700
Last modified on 2020-07-19 13:20:37 -0700
Version trunk
Hardware PC Linux
CC blitzrakete@gmail.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
Combination of aggregate CTAD and inheritance makes -Wmissing-braces wrong.

For example, take a tuple class with the usual CTAD:
https://wandbox.org/permlink/USZGcupYvTtP8D6D

  template <typename...> struct tuple;
  template <typename... T> tuple(T...) -> tuple<T...>;

Implement it as an aggregate, by explicit specializations:

  template <> struct tuple<> {};
  template <typename A> struct tuple<A> {A a;};
  template <typename A, typename B> struct tuple<A,B> {A a; B b;};
  ... & etc.

Now, 'tie' is usually implemented as a helper 'make' function tie(...)
Instead, implement tie as a class inheriting from tuple, with CTAD

  template <typename... T> struct tie : tuple<T...> {};
  template <typename... T> tie(T&...) -> tie<T&...>;

along with an extra tuple CTAD converting from tie to tuple

  template <typename... T> tuple(tie<T...>) -> tuple<T...>;

Now, usage of tie looks like this:

  bool up = true;
  tuple t = tie{up};

warning: suggest braces around initialization of subobject [-Wmissing-braces]
tuple t = tie{up};
              ^~
              { }
1 warning generated.

However, this warning is incorrect here -
adding the suggested braces breaks the CTAD deduction.
Quuxplusone commented 4 years ago
(Incidentally) bogus warnings galore for this sketchy implementation
of a make_tuple-like helper that copies all args, including arrays,
by bit_cast-ing from a by-copy closure to the tuple type:
https://wandbox.org/permlink/xqUPQnqFhi7WxeVn

  template <typename... T>
  constexpr auto copy_tuple(T&&... a) -> tuple<remove_cvref_t<T>...> {
    return {__builtin_bit_cast(tuple<remove_cvref_t<T>...>,[a...]{})};
  }

  int a[1]{1};
  int b[2]{2,3};
  int c[3]{4,5,6};
  auto tri = copy_tuple(a,b,c); // tuple<int[1],int[2],int[3]>

Gives:

 warning: lambda capture 'a' is not used [-Wunused-lambda-capture]
     return {__builtin_bit_cast(tuple<std::remove_cvref_t<T>...>,[a...]{})};
                                                                  ^
 note: in instantiation of function template specialization 'copy_tuple' ...
 warning: lambda capture 'a' is not used [-Wunused-lambda-capture]
     return {__builtin_bit_cast(tuple<std::remove_cvref_t<T>...>,[a...]{})};
 warning: lambda capture 'a' is not used [-Wunused-lambda-capture]
 3 warnings generated.

The lambda captures are clearly used... only purely for their free copy.

(I'm aware that closures have undefined layout so this technique is sketchy.)

p.s.
(This helper function would not be needed if C++ arrays had copy-semantics
 as proposed in P1997;
 modify the CTAD of the aggregate tuple implementation:

  template <typename... T> tuple(T&&...) -> tuple<remove_cvref_t<T>...>;

 Then with P1997:

  auto tri = tuple(a,b,c);

 succeeds in initializing the deduced array members from array variables.)