This solves a conflict between late changes to the C++17 library and core language, which make tuple_size<const T>::value cause errors for const structured binding declarations. The problem is that LWG 2770 wants tuple_size<cv T> to be complete, but sometimes have no value member, but the core language for structured bindings barfs on a complete type with no value member.
It's possible this will be fixed in core (e.g. by only trying to use tuple_size when it's complete _and_ has a usable value member) but for now let's just fix it in the library. This is consistent with the solution in libc++ too. PR libstdc++/78939 * include/std/utility (tuple_size<cv T>): Only define partial specializations when tuple_size<T>::value is valid. * testsuite/20_util/tuple/78939.cc: New. * testsuite/20_util/tuple/cv_tuple_size_neg.cc: New. Tested powerpc64le-linux, committed to trunk.
commit f72d64f99385f51efb8f437618f084335fe64f89 Author: Jonathan Wakely <jwak...@redhat.com> Date: Wed Mar 8 03:07:48 2017 +0000 PR libstdc++/78939 make tuple_size<cv T> depend on tuple_size<T> PR libstdc++/78939 * include/std/utility (tuple_size<cv T>): Only define partial specializations when tuple_size<T>::value is valid. * testsuite/20_util/tuple/78939.cc: New. * testsuite/20_util/tuple/cv_tuple_size_neg.cc: New. diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index 188fcc2..c18bcb6 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -88,24 +88,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct tuple_size; // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2770. tuple_size<const T> specialization is not SFINAE compatible - template<typename _Tp, typename = void> - struct __tuple_size_cv_impl { }; - - template<typename _Tp> - struct __tuple_size_cv_impl<_Tp, __void_t<decltype(tuple_size<_Tp>::value)>> - : integral_constant<size_t, tuple_size<_Tp>::value> { }; - - // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2313. tuple_size should always derive from integral_constant<size_t, N> - template<typename _Tp> - struct tuple_size<const _Tp> : __tuple_size_cv_impl<_Tp> { }; + // 2770. tuple_size<const T> specialization is not SFINAE compatible + + template<typename _Tp, + typename _Up = typename remove_cv<_Tp>::type, + typename = typename enable_if<is_same<_Tp, _Up>::value>::type, + size_t = tuple_size<_Tp>::value> + using __enable_if_has_tuple_size = _Tp; template<typename _Tp> - struct tuple_size<volatile _Tp> : __tuple_size_cv_impl<_Tp> { }; + struct tuple_size<const __enable_if_has_tuple_size<_Tp>> + : public tuple_size<_Tp> { }; template<typename _Tp> - struct tuple_size<const volatile _Tp> : __tuple_size_cv_impl<_Tp> { }; + struct tuple_size<volatile __enable_if_has_tuple_size<_Tp>> + : public tuple_size<_Tp> { }; + + template<typename _Tp> + struct tuple_size<const volatile __enable_if_has_tuple_size<_Tp>> + : public tuple_size<_Tp> { }; /// Gives the type of the ith element of a given tuple type. template<std::size_t __i, typename _Tp> diff --git a/libstdc++-v3/testsuite/20_util/tuple/78939.cc b/libstdc++-v3/testsuite/20_util/tuple/78939.cc new file mode 100644 index 0000000..bab143b --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/78939.cc @@ -0,0 +1,49 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++1z } } + +// PR libstdc++/78939 + +#include <utility> + +struct A { int i, j; }; + +int +test01() +{ + A a{}; + const auto [i, j] = a; + return i + j; +} + +int +test02() +{ + A a{}; + volatile auto [i, j] = a; + return i + j; +} + +int +test03() +{ + A a{}; + const volatile auto [i, j] = a; + return i + j; +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/cv_tuple_size_neg.cc b/libstdc++-v3/testsuite/20_util/tuple/cv_tuple_size_neg.cc new file mode 100644 index 0000000..450ed89 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/cv_tuple_size_neg.cc @@ -0,0 +1,35 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++11 } } + +#include <tuple> + +// PR libstdc++/78939 + +std::tuple_size<const int> ic; // { dg-error "incomplete" } +std::tuple_size<volatile int> iv; // { dg-error "incomplete" } +std::tuple_size<const volatile int> icv; // { dg-error "incomplete" } + +struct A { }; +std::tuple_size<const A> ac; // { dg-error "incomplete" } +std::tuple_size<volatile A> av; // { dg-error "incomplete" } +std::tuple_size<const volatile A> acv; // { dg-error "incomplete" } + +std::tuple_size<const void> vc; // { dg-error "incomplete" } +std::tuple_size<volatile void> vv; // { dg-error "incomplete" } +std::tuple_size<const volatile void> vcv; // { dg-error "incomplete" }