<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - implementing tuple as an aggregate type triggers -Wmissing-braces warning"
   href="https://bugs.llvm.org/show_bug.cgi?id=52277">52277</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>implementing tuple as an aggregate type triggers -Wmissing-braces warning
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>C++2a
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>mte.zych@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>blitzrakete@gmail.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Hello!

I've recently implemented cxx::tuple<>, which is like std::tuple<>,
except that it's an aggregate type and a structural type.

namespace cxx
{
    namespace detail
    {
        template <std::size_t index, typename type>
        struct element { type value; };

        template <typename index_sequence, typename ... types>
        struct tuple_base;

        template <std::size_t ... indices, typename ... types>
        struct tuple_base <std::index_sequence<indices...>, types...>
        :
            element<indices, types>...
        { };
    }

    template <typename ... types>
    struct tuple
    :
        detail::tuple_base<std::index_sequence_for<types...>, types...>
    {
    };

    template <typename ... types>
    tuple(types...) -> tuple<types...>;
}


Essentially the cxx::tuple<> inherits from cxx::detal::tuple_base<>,
which itself inherits from cxx::detail::element<> structs,
which are wrapping values of all tuple elements.

+-------------------------------------------------------------------------+
| cxx::tuple<int, float, char>                                            |
| +---------------------------------------------------------------------+ |
| | cxx::detail::tuple_base<std::index_sequence<0,1,2>, int,float,char> | |
| | +-----------------------------------------------------------------+ | |
| | | cxx::detail::element<0, int>                                    | | |
| | |                                                                 | | |
| | | int   value;                                                    | | |
| | +-----------------------------------------------------------------+ | |
| | +-----------------------------------------------------------------+ | |
| | | cxx::detail::element<1, float>                                  | | |
| | |                                                                 | | |
| | | float value;                                                    | | |
| | +-----------------------------------------------------------------+ | |
| | +-----------------------------------------------------------------+ | |
| | | cxx::detail::element<2, char>                                   | | |
| | |                                                                 | | |
| | | char  value;                                                    | | |
| | +-----------------------------------------------------------------+ | |
| +---------------------------------------------------------------------+ |
+-------------------------------------------------------------------------+


This alternative implementation strategy has couple of advantages:

 1. The cxx::tuple<> is an aggregate type, which allows initializing
    tuple elements of non-movable and non-copyable types directly in-place:

    auto latches = cxx::tuple { std::latch { 2 }, std::latch { 4 } };

 2. The cxx::tuple<> is also a structural type,
    which means it can be used as a non-type template parameter:

    template <cxx::tuple<int, float, char>>
    auto fn () -> void { }

More complete implementation of the cxx::tuple<> can be found here:

 -
<a href="https://github.com/mtezych/cpp/blob/master/data-structures/include/cxx/tuple.hxx">https://github.com/mtezych/cpp/blob/master/data-structures/include/cxx/tuple.hxx</a>


Unfortunately there is one problem with cxx::tuple<>,
that is, it triggers "-Wmissing-braces" warning in Clang,
since its recommended method of initialization relies on brace-elision:

  auto tuple = cxx::tuple { 8, 0.4f, '#' };

  - <a href="https://godbolt.org/z/WfoTbrG5E">https://godbolt.org/z/WfoTbrG5E</a>

Sure, it's possible to specify all braces during initialization,
but doing so makes code so much less readable:

  auto tuple = cxx::tuple<int, float, char> { { { 8 }, { 0.4f }, { '#' } } };


Note that, both GCC and MSVC are not warning about brace-elision:

 ~ [GCC ] -> <a href="https://godbolt.org/z/WdoKrsabj">https://godbolt.org/z/WdoKrsabj</a>
 ~ [MSVC] -> <a href="https://godbolt.org/z/8q7hxb7qe">https://godbolt.org/z/8q7hxb7qe</a>

Actually, GCC completely removed "-Wmissing-braces" warning from
the set of warnings enabled by the "-Wall" compiler flag, back in 2012:

 - <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25137">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25137</a>


Interestingly Clang uses different approach - it white lists some cases,
which are considered an idiomatic usage of brace-elision.

 - <a href="https://reviews.llvm.org/rG64c24f493e5f4637ee193f10f469cdd2695b4ba6">https://reviews.llvm.org/rG64c24f493e5f4637ee193f10f469cdd2695b4ba6</a>
 - <a href="https://reviews.llvm.org/rG283e2076f6a6f23629475a25c64173843e72cf61">https://reviews.llvm.org/rG283e2076f6a6f23629475a25c64173843e72cf61</a>

In short, after Hana Dusíková and Richard Smith commited their changes,
Clang consideres brace-elision idiomatic when
the one and only field is recursively initialized within an aggregate class.

 -
<a href="https://github.com/llvm/llvm-project/blob/release/13.x/clang/lib/Sema/SemaInit.cpp#L999">https://github.com/llvm/llvm-project/blob/release/13.x/clang/lib/Sema/SemaInit.cpp#L999</a>


Personally, I think that it's worth considering
extending idiomatic usages of brace-elision to more cases.

To be clear, I don't want to make buggy code more difficult to detect,
but brace-elision is a C++ feature, which has justified usages,
such as initializing cxx::tuple<>, so Clang shouldn't discourage them.

Could we work out a more general rule, which would distinguish
intentional usages of brace-elision from programming mistakes,
resulting from accidental/erroneous usages of brace-elision?

What comes to my mind is permitting brace-elision in cases, when
all extra braces have been elided and only single pair of braces was used.
This rule would make brace elision kind of "all or nothing",
allowing a developer to signal that brace-elision should take place.

 - <a href="https://godbolt.org/z/rx8an3Eza">https://godbolt.org/z/rx8an3Eza</a>


What do you think?

Thanks, Mateusz</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>