Implement the <tuple> part of C++20 p1032 Misc constexpr bits.
diff mbox series

Message ID df6f1faa65f64b2190ce1aeb4e843ac7@alionscience.com
State New
Headers show
Series
  • Implement the <tuple> part of C++20 p1032 Misc constexpr bits.
Related show

Commit Message

Smith-Rowland, Edward M Nov. 9, 2019, 2:07 a.m. UTC
Here is the <tuple> part of C++20 p1032 Misc constexpr bits.

Tested on x86_64-linux. OK?

Ed

Comments

Jonathan Wakely Nov. 14, 2019, 3:55 p.m. UTC | #1
On 09/11/19 02:07 +0000, Smith-Rowland, Edward M wrote:
>Here is the <tuple> part of C++20 p1032 Misc constexpr bits.
>
>Tested on x86_64-linux. OK?

OK for trunk, thanks.
Christophe Lyon Nov. 20, 2019, 9:47 a.m. UTC | #2
On Thu, 14 Nov 2019 at 16:55, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On 09/11/19 02:07 +0000, Smith-Rowland, Edward M wrote:
> >Here is the <tuple> part of C++20 p1032 Misc constexpr bits.
> >
> >Tested on x86_64-linux. OK?
>
> OK for trunk, thanks.
>

Hi,

The new test constexpr_allocator_arg_t.cc fails on arm and aarch64 and
many other targets according to gcc-testresults.
Is that expected?

Christophe
Ville Voutilainen Nov. 20, 2019, 10:10 a.m. UTC | #3
On Wed, 20 Nov 2019 at 11:47, Christophe Lyon
<christophe.lyon@linaro.org> wrote:
>
> On Thu, 14 Nov 2019 at 16:55, Jonathan Wakely <jwakely@redhat.com> wrote:
> >
> > On 09/11/19 02:07 +0000, Smith-Rowland, Edward M wrote:
> > >Here is the <tuple> part of C++20 p1032 Misc constexpr bits.
> > >
> > >Tested on x86_64-linux. OK?
> >
> > OK for trunk, thanks.
> >
>
> Hi,
>
> The new test constexpr_allocator_arg_t.cc fails on arm and aarch64 and
> many other targets according to gcc-testresults.
> Is that expected?

No, that's not expected. Can you give a link to the build log?
Christophe Lyon Nov. 20, 2019, 10:16 a.m. UTC | #4
On Wed, 20 Nov 2019 at 11:10, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
>
> On Wed, 20 Nov 2019 at 11:47, Christophe Lyon
> <christophe.lyon@linaro.org> wrote:
> >
> > On Thu, 14 Nov 2019 at 16:55, Jonathan Wakely <jwakely@redhat.com> wrote:
> > >
> > > On 09/11/19 02:07 +0000, Smith-Rowland, Edward M wrote:
> > > >Here is the <tuple> part of C++20 p1032 Misc constexpr bits.
> > > >
> > > >Tested on x86_64-linux. OK?
> > >
> > > OK for trunk, thanks.
> > >
> >
> > Hi,
> >
> > The new test constexpr_allocator_arg_t.cc fails on arm and aarch64 and
> > many other targets according to gcc-testresults.
> > Is that expected?
>
> No, that's not expected. Can you give a link to the build log?

On (cross) aarch64, I can see:
FAIL: 20_util/tuple/cons/constexpr_allocator_arg_t.cc (test for excess errors)
Excess errors:
/libstdc++-v3/testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc:48:
error: non-constant condition for static assertion
/libstdc++-v3/testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc:48:
  in 'constexpr' expansion of 'test_tuple()'
/libstdc++-v3/testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc:31:
  in 'constexpr' expansion of 'ta.std::tuple<int, double,
double>::tuple<std::allocator<int> >(std::allocator_arg, alloc)'
/aci-gcc-fsf/builds/gcc-fsf-gccsrc/obj-aarch64-none-linux-gnu/gcc3/aarch64-none-linux-gnu/libstdc++-v3/include/tuple:705:
error: 'constexpr std::_Tuple_impl<_Idx, _Head, _Tail
...>::_Tuple_impl(std::allocator_arg_t, const _Alloc&) [with _Alloc =
std::allocator<int>; long unsigned int _Idx = 0; _Head = int; _Tail =
{double, double}]' called in a constant expression
/aci-gcc-fsf/builds/gcc-fsf-gccsrc/obj-aarch64-none-linux-gnu/gcc3/aarch64-none-linux-gnu/libstdc++-v3/include/tuple:251:
error: call to non-'constexpr' function 'std::__uses_alloc_t<_Tp,
_Alloc, _Args ...> std::__use_alloc(const _Alloc&) [with _Tp = int;
_Alloc = std::allocator<int>; _Args = {}; std::__uses_alloc_t<_Tp,
_Alloc, _Args ...> = std::__uses_alloc_t<int, std::allocator<int> >]'


I see it failing at r278333, was it fixed since then?
Ville Voutilainen Nov. 20, 2019, 11:01 a.m. UTC | #5
On Wed, 20 Nov 2019 at 12:16, Christophe Lyon
<christophe.lyon@linaro.org> wrote:
>
> On Wed, 20 Nov 2019 at 11:10, Ville Voutilainen
> <ville.voutilainen@gmail.com> wrote:
> >
> > On Wed, 20 Nov 2019 at 11:47, Christophe Lyon
> > <christophe.lyon@linaro.org> wrote:
> > >
> > > On Thu, 14 Nov 2019 at 16:55, Jonathan Wakely <jwakely@redhat.com> wrote:
> > > >
> > > > On 09/11/19 02:07 +0000, Smith-Rowland, Edward M wrote:
> > > > >Here is the <tuple> part of C++20 p1032 Misc constexpr bits.
> > > > >
> > > > >Tested on x86_64-linux. OK?
> > > >
> > > > OK for trunk, thanks.
> > > >
> > >
> > > Hi,
> > >
> > > The new test constexpr_allocator_arg_t.cc fails on arm and aarch64 and
> > > many other targets according to gcc-testresults.
> > > Is that expected?
> >
> > No, that's not expected. Can you give a link to the build log?
>
> On (cross) aarch64, I can see:
> FAIL: 20_util/tuple/cons/constexpr_allocator_arg_t.cc (test for excess errors)
> Excess errors:
> /libstdc++-v3/testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc:48:
> error: non-constant condition for static assertion
> /libstdc++-v3/testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc:48:
>   in 'constexpr' expansion of 'test_tuple()'
> /libstdc++-v3/testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc:31:
>   in 'constexpr' expansion of 'ta.std::tuple<int, double,
> double>::tuple<std::allocator<int> >(std::allocator_arg, alloc)'
> /aci-gcc-fsf/builds/gcc-fsf-gccsrc/obj-aarch64-none-linux-gnu/gcc3/aarch64-none-linux-gnu/libstdc++-v3/include/tuple:705:
> error: 'constexpr std::_Tuple_impl<_Idx, _Head, _Tail
> ...>::_Tuple_impl(std::allocator_arg_t, const _Alloc&) [with _Alloc =
> std::allocator<int>; long unsigned int _Idx = 0; _Head = int; _Tail =
> {double, double}]' called in a constant expression
> /aci-gcc-fsf/builds/gcc-fsf-gccsrc/obj-aarch64-none-linux-gnu/gcc3/aarch64-none-linux-gnu/libstdc++-v3/include/tuple:251:
> error: call to non-'constexpr' function 'std::__uses_alloc_t<_Tp,
> _Alloc, _Args ...> std::__use_alloc(const _Alloc&) [with _Tp = int;
> _Alloc = std::allocator<int>; _Args = {}; std::__uses_alloc_t<_Tp,
> _Alloc, _Args ...> = std::__uses_alloc_t<int, std::allocator<int> >]'
>
>
> I see it failing at r278333, was it fixed since then?

Yes, in r278373.

Patch
diff mbox series

Index: include/std/tuple
===================================================================
--- include/std/tuple	(revision 277944)
+++ include/std/tuple	(working copy)
@@ -132,6 +132,7 @@ 
         constexpr _Head_base(_UHead&& __h)
 	: _M_head_impl(std::forward<_UHead>(__h)) { }
 
+      _GLIBCXX20_CONSTEXPR
       _Head_base(allocator_arg_t, __uses_alloc0)
       : _M_head_impl() { }
 
@@ -144,6 +145,7 @@ 
 	: _M_head_impl(*__a._M_a) { }
 
       template<typename _UHead>
+	_GLIBCXX20_CONSTEXPR
 	_Head_base(__uses_alloc0, _UHead&& __uhead)
 	: _M_head_impl(std::forward<_UHead>(__uhead)) { }
 
@@ -243,6 +245,7 @@ 
 		(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a)
 	: _Inherited(__tag, __a),
           _Base(__tag, __use_alloc<_Head>(__a)) { }
@@ -256,6 +259,7 @@ 
       template<typename _Alloc, typename _UHead, typename... _UTail,
                typename = typename enable_if<sizeof...(_Tail)
 					     == sizeof...(_UTail)>::type>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            _UHead&& __head, _UTail&&... __tail)
 	: _Inherited(__tag, __a, std::forward<_UTail>(__tail)...),
@@ -263,6 +267,7 @@ 
 	        std::forward<_UHead>(__head)) { }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
         _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            const _Tuple_impl& __in)
 	: _Inherited(__tag, __a, _M_tail(__in)),
@@ -269,6 +274,7 @@ 
           _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            _Tuple_impl&& __in)
 	: _Inherited(__tag, __a, std::move(_M_tail(__in))),
@@ -276,6 +282,7 @@ 
 	        std::forward<_Head>(_M_head(__in))) { }
 
       template<typename _Alloc, typename... _UElements>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            const _Tuple_impl<_Idx, _UElements...>& __in)
 	: _Inherited(__tag, __a,
@@ -284,6 +291,7 @@ 
 		_Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { }
 
       template<typename _Alloc, typename _UHead, typename... _UTails>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            _Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
 	: _Inherited(__tag, __a, std::move
@@ -293,6 +301,7 @@ 
 		(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { }
 
       template<typename... _UElements>
+	_GLIBCXX20_CONSTEXPR
         void
         _M_assign(const _Tuple_impl<_Idx, _UElements...>& __in)
         {
@@ -302,6 +311,7 @@ 
 	}
 
       template<typename _UHead, typename... _UTails>
+	_GLIBCXX20_CONSTEXPR
         void
         _M_assign(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
         {
@@ -312,6 +322,7 @@ 
 	}
 
     protected:
+      _GLIBCXX20_CONSTEXPR
       void
       _M_swap(_Tuple_impl& __in)
       {
@@ -369,6 +380,7 @@ 
 	{ }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a)
 	: _Base(__tag, __use_alloc<_Head>(__a)) { }
 
@@ -378,6 +390,7 @@ 
 	: _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { }
 
       template<typename _Alloc, typename _UHead>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            _UHead&& __head)
 	: _Base(__use_alloc<_Head, _Alloc, _UHead>(__a),
@@ -384,11 +397,13 @@ 
 	        std::forward<_UHead>(__head)) { }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
         _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            const _Tuple_impl& __in)
 	: _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            _Tuple_impl&& __in)
 	: _Base(__use_alloc<_Head, _Alloc, _Head>(__a),
@@ -395,6 +410,7 @@ 
 	        std::forward<_Head>(_M_head(__in))) { }
 
       template<typename _Alloc, typename _UHead>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            const _Tuple_impl<_Idx, _UHead>& __in)
 	: _Base(__use_alloc<_Head, _Alloc, _Head>(__a),
@@ -401,6 +417,7 @@ 
 		_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { }
 
       template<typename _Alloc, typename _UHead>
+	_GLIBCXX20_CONSTEXPR
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            _Tuple_impl<_Idx, _UHead>&& __in)
 	: _Base(__use_alloc<_Head, _Alloc, _UHead>(__a),
@@ -408,6 +425,7 @@ 
 	{ }
 
       template<typename _UHead>
+	_GLIBCXX20_CONSTEXPR
         void
         _M_assign(const _Tuple_impl<_Idx, _UHead>& __in)
         {
@@ -415,6 +433,7 @@ 
 	}
 
       template<typename _UHead>
+	_GLIBCXX20_CONSTEXPR
         void
         _M_assign(_Tuple_impl<_Idx, _UHead>&& __in)
         {
@@ -423,6 +442,7 @@ 
 	}
 
     protected:
+      _GLIBCXX20_CONSTEXPR
       void
       _M_swap(_Tuple_impl& __in)
       {
@@ -680,11 +700,13 @@ 
 
       template<typename _Alloc,
 	       _ImplicitDefaultCtor<is_object<_Alloc>::value> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a)
 	: _Inherited(__tag, __a) { }
 
       template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1),
 	       _ImplicitCtor<_NotEmpty, const _Elements&...> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const _Elements&... __elements)
 	: _Inherited(__tag, __a, __elements...) { }
@@ -691,6 +713,7 @@ 
 
       template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1),
 	       _ExplicitCtor<_NotEmpty, const _Elements&...> = false>
+	_GLIBCXX20_CONSTEXPR
 	explicit
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const _Elements&... __elements)
@@ -699,6 +722,7 @@ 
       template<typename _Alloc, typename... _UElements,
 	       bool _Valid = __valid_args<_UElements...>(),
 	       _ImplicitCtor<_Valid, _UElements...> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      _UElements&&... __elements)
 	: _Inherited(__tag, __a, std::forward<_UElements>(__elements)...)
@@ -707,6 +731,7 @@ 
       template<typename _Alloc, typename... _UElements,
 		 bool _Valid = __valid_args<_UElements...>(),
 	       _ExplicitCtor<_Valid, _UElements...> = false>
+	_GLIBCXX20_CONSTEXPR
 	explicit
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      _UElements&&... __elements)
@@ -714,10 +739,12 @@ 
 	{ }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in)
 	: _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in)
 	: _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { }
 
@@ -725,6 +752,7 @@ 
 	       bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
 			     && !__use_other_ctor<const tuple<_UElements...>&>(),
 	       _ImplicitCtor<_Valid, const _UElements&...> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const tuple<_UElements...>& __in)
 	: _Inherited(__tag, __a,
@@ -735,6 +763,7 @@ 
 	       bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
 			     && !__use_other_ctor<const tuple<_UElements...>&>(),
 	       _ExplicitCtor<_Valid, const _UElements&...> = false>
+	_GLIBCXX20_CONSTEXPR
 	explicit
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const tuple<_UElements...>& __in)
@@ -746,6 +775,7 @@ 
 	       bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
 			     && !__use_other_ctor<tuple<_UElements...>&&>(),
 	       _ImplicitCtor<_Valid, _UElements...> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      tuple<_UElements...>&& __in)
 	: _Inherited(__tag, __a,
@@ -756,6 +786,7 @@ 
 	       bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
 			     && !__use_other_ctor<tuple<_UElements...>&&>(),
 	       _ExplicitCtor<_Valid, _UElements...> = false>
+	_GLIBCXX20_CONSTEXPR
 	explicit
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      tuple<_UElements...>&& __in)
@@ -765,6 +796,7 @@ 
 
       // tuple assignment
 
+      _GLIBCXX20_CONSTEXPR
       tuple&
       operator=(typename conditional<__assignable<const _Elements&...>(),
 				     const tuple&,
@@ -775,6 +807,7 @@ 
 	return *this;
       }
 
+      _GLIBCXX20_CONSTEXPR
       tuple&
       operator=(typename conditional<__assignable<_Elements...>(),
 				     tuple&&,
@@ -786,6 +819,7 @@ 
       }
 
       template<typename... _UElements>
+	_GLIBCXX20_CONSTEXPR
 	__enable_if_t<__assignable<const _UElements&...>(), tuple&>
 	operator=(const tuple<_UElements...>& __in)
 	noexcept(__nothrow_assignable<const _UElements&...>())
@@ -795,6 +829,7 @@ 
 	}
 
       template<typename... _UElements>
+	_GLIBCXX20_CONSTEXPR
 	__enable_if_t<__assignable<_UElements...>(), tuple&>
 	operator=(tuple<_UElements...>&& __in)
 	noexcept(__nothrow_assignable<_UElements...>())
@@ -804,6 +839,7 @@ 
 	}
 
       // tuple swap
+      _GLIBCXX20_CONSTEXPR
       void
       swap(tuple& __in)
       noexcept(__and_<__is_nothrow_swappable<_Elements>...>::value)
@@ -834,8 +870,10 @@ 
       tuple() = default;
       // No-op allocator constructors.
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t, const _Alloc&) noexcept { }
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept { }
     };
 
@@ -1015,11 +1053,13 @@ 
 
       template<typename _Alloc,
 	       _ImplicitDefaultCtor<is_object<_Alloc>::value, _T1, _T2> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a)
 	: _Inherited(__tag, __a) { }
 
       template<typename _Alloc, bool _Dummy = true,
 	       _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const _T1& __a1, const _T2& __a2)
 	: _Inherited(__tag, __a, __a1, __a2) { }
@@ -1027,6 +1067,7 @@ 
       template<typename _Alloc, bool _Dummy = true,
 	       _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false>
 	explicit
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const _T1& __a1, const _T2& __a2)
 	: _Inherited(__tag, __a, __a1, __a2) { }
@@ -1033,6 +1074,7 @@ 
 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ImplicitCtor<true, _U1, _U2> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2)
 	: _Inherited(__tag, __a, std::forward<_U1>(__a1),
 	             std::forward<_U2>(__a2)) { }
@@ -1040,6 +1082,7 @@ 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ExplicitCtor<true, _U1, _U2> = false>
 	explicit
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      _U1&& __a1, _U2&& __a2)
 	: _Inherited(__tag, __a, std::forward<_U1>(__a1),
@@ -1046,15 +1089,18 @@ 
 	             std::forward<_U2>(__a2)) { }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in)
 	: _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { }
 
       template<typename _Alloc>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in)
 	: _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { }
 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ImplicitCtor<true, const _U1&, const _U2&> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const tuple<_U1, _U2>& __in)
 	: _Inherited(__tag, __a,
@@ -1064,6 +1110,7 @@ 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ExplicitCtor<true, const _U1&, const _U2&> = false>
 	explicit
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const tuple<_U1, _U2>& __in)
 	: _Inherited(__tag, __a,
@@ -1072,6 +1119,7 @@ 
 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ImplicitCtor<true, _U1, _U2> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in)
 	: _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in))
 	{ }
@@ -1079,6 +1127,7 @@ 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ExplicitCtor<true, _U1, _U2> = false>
 	explicit
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in)
 	: _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in))
 	{ }
@@ -1085,6 +1134,7 @@ 
 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ImplicitCtor<true, const _U1&, const _U2&> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const pair<_U1, _U2>& __in)
 	: _Inherited(__tag, __a, __in.first, __in.second) { }
@@ -1092,6 +1142,7 @@ 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ExplicitCtor<true, const _U1&, const _U2&> = false>
 	explicit
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const pair<_U1, _U2>& __in)
 	: _Inherited(__tag, __a, __in.first, __in.second) { }
@@ -1098,6 +1149,7 @@ 
 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ImplicitCtor<true, _U1, _U2> = true>
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
 	: _Inherited(__tag, __a, std::forward<_U1>(__in.first),
 		     std::forward<_U2>(__in.second)) { }
@@ -1105,10 +1157,14 @@ 
       template<typename _Alloc, typename _U1, typename _U2,
 	       _ExplicitCtor<true, _U1, _U2> = false>
 	explicit
+	_GLIBCXX20_CONSTEXPR
 	tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
 	: _Inherited(__tag, __a, std::forward<_U1>(__in.first),
 		     std::forward<_U2>(__in.second)) { }
 
+      // Tuple assignment.
+
+      _GLIBCXX20_CONSTEXPR
       tuple&
       operator=(typename conditional<__assignable<const _T1&, const _T2&>(),
 				     const tuple&,
@@ -1119,6 +1175,7 @@ 
 	return *this;
       }
 
+      _GLIBCXX20_CONSTEXPR
       tuple&
       operator=(typename conditional<__assignable<_T1, _T2>(),
 				     tuple&&,
@@ -1130,6 +1187,7 @@ 
       }
 
       template<typename _U1, typename _U2>
+	_GLIBCXX20_CONSTEXPR
 	__enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
 	operator=(const tuple<_U1, _U2>& __in)
 	noexcept(__nothrow_assignable<const _U1&, const _U2&>())
@@ -1139,6 +1197,7 @@ 
 	}
 
       template<typename _U1, typename _U2>
+	_GLIBCXX20_CONSTEXPR
 	__enable_if_t<__assignable<_U1, _U2>(), tuple&>
 	operator=(tuple<_U1, _U2>&& __in)
 	noexcept(__nothrow_assignable<_U1, _U2>())
@@ -1148,6 +1207,7 @@ 
 	}
 
       template<typename _U1, typename _U2>
+	_GLIBCXX20_CONSTEXPR
 	__enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
 	operator=(const pair<_U1, _U2>& __in)
 	noexcept(__nothrow_assignable<const _U1&, const _U2&>())
@@ -1158,6 +1218,7 @@ 
 	}
 
       template<typename _U1, typename _U2>
+	_GLIBCXX20_CONSTEXPR
 	__enable_if_t<__assignable<_U1, _U2>(), tuple&>
 	operator=(pair<_U1, _U2>&& __in)
 	noexcept(__nothrow_assignable<_U1, _U2>())
@@ -1167,6 +1228,7 @@ 
 	  return *this;
 	}
 
+      _GLIBCXX20_CONSTEXPR
       void
       swap(tuple& __in)
       noexcept(__and_<__is_nothrow_swappable<_T1>,
@@ -1521,6 +1583,7 @@ 
 
   /// swap
   template<typename... _Elements>
+    _GLIBCXX20_CONSTEXPR
     inline
 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
     // Constrained free swap overload, see p0185r1
@@ -1535,6 +1598,7 @@ 
 
 #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
   template<typename... _Elements>
+    _GLIBCXX20_CONSTEXPR
     typename enable_if<!__and_<__is_swappable<_Elements>...>::value>::type
     swap(tuple<_Elements...>&, tuple<_Elements...>&) = delete;
 #endif
@@ -1570,7 +1634,8 @@ 
   */
   template<class _T1, class _T2>
     template<typename... _Args1, typename... _Args2>
-      _GLIBCXX20_CONSTEXPR inline
+      _GLIBCXX20_CONSTEXPR
+      inline
       pair<_T1, _T2>::
       pair(piecewise_construct_t,
 	   tuple<_Args1...> __first, tuple<_Args2...> __second)
Index: include/bits/uses_allocator.h
===================================================================
--- include/bits/uses_allocator.h	(revision 277944)
+++ include/bits/uses_allocator.h	(working copy)
@@ -72,7 +72,7 @@ 
 
   struct __uses_alloc0 : __uses_alloc_base
   {
-    struct _Sink { void operator=(const void*) { } } _M_a;
+    struct _Sink { void _GLIBCXX20_CONSTEXPR operator=(const void*) { } } _M_a;
   };
 
   template<typename _Alloc>
@@ -109,6 +109,7 @@ 
       __uses_alloc<uses_allocator<_Tp, _Alloc>::value, _Tp, _Alloc, _Args...>;
 
   template<typename _Tp, typename _Alloc, typename... _Args>
+    _GLIBCXX20_CONSTEXPR
     inline __uses_alloc_t<_Tp, _Alloc, _Args...>
     __use_alloc(const _Alloc& __a)
     {
Index: testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc
===================================================================
--- testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc	(nonexistent)
+++ testsuite/20_util/tuple/cons/constexpr_allocator_arg_t.cc	(working copy)
@@ -0,0 +1,48 @@ 
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+//
+// Copyright (C) 2019 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/>.
+
+#include <memory>
+#include <tuple>
+
+const std::allocator<int> alloc{};
+
+constexpr bool
+test_tuple()
+{
+  auto ok = true;
+
+  std::tuple<int, double, double> ta(std::allocator_arg, alloc);
+  std::tuple<int, double, double> tb(std::allocator_arg, alloc, 0, 3.456, 6.789);
+  std::tuple<int, double, double> tc(std::allocator_arg, alloc, 0, 3.456f, 6.789f);
+  std::tuple<int, double, double> td(std::allocator_arg, alloc, tb);
+  std::tuple<int, double, double> te(std::allocator_arg, alloc, std::move(tb));
+
+  std::tuple<int, float, float> tf(std::allocator_arg, alloc, 0, 3.456f, 6.789f);
+  std::tuple<int, double, double> tg(std::allocator_arg, alloc, tf);
+  std::tuple<int, double, double> th(std::allocator_arg, alloc, std::move(tf));
+
+  std::pair<int, float> pf(12, 3.142f);
+  std::tuple<int, double> ti(std::allocator_arg, alloc, pf);
+  std::tuple<int, double> tj(std::allocator_arg, alloc, std::move(pf));
+
+  return ok;
+}
+
+static_assert(test_tuple());