[llvm-bugs] [Bug 52277] New: implementing tuple as an aggregate type triggers -Wmissing-braces warning
via llvm-bugs
llvm-bugs at lists.llvm.org
Sat Oct 23 14:12:46 PDT 2021
https://bugs.llvm.org/show_bug.cgi?id=52277
Bug ID: 52277
Summary: implementing tuple as an aggregate type triggers
-Wmissing-braces warning
Product: clang
Version: trunk
Hardware: PC
OS: Linux
Status: NEW
Severity: enhancement
Priority: P
Component: C++2a
Assignee: unassignedclangbugs at nondot.org
Reporter: mte.zych at gmail.com
CC: blitzrakete at gmail.com, erik.pilkington at gmail.com,
llvm-bugs at lists.llvm.org, richard-llvm at metafoo.co.uk
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:
-
https://github.com/mtezych/cpp/blob/master/data-structures/include/cxx/tuple.hxx
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, '#' };
- https://godbolt.org/z/WfoTbrG5E
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 ] -> https://godbolt.org/z/WdoKrsabj
~ [MSVC] -> https://godbolt.org/z/8q7hxb7qe
Actually, GCC completely removed "-Wmissing-braces" warning from
the set of warnings enabled by the "-Wall" compiler flag, back in 2012:
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25137
Interestingly Clang uses different approach - it white lists some cases,
which are considered an idiomatic usage of brace-elision.
- https://reviews.llvm.org/rG64c24f493e5f4637ee193f10f469cdd2695b4ba6
- https://reviews.llvm.org/rG283e2076f6a6f23629475a25c64173843e72cf61
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.
-
https://github.com/llvm/llvm-project/blob/release/13.x/clang/lib/Sema/SemaInit.cpp#L999
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.
- https://godbolt.org/z/rx8an3Eza
What do you think?
Thanks, Mateusz
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20211023/119f9d70/attachment.html>
More information about the llvm-bugs
mailing list