Re: [PATCH] assert that deleting by pointer to base in unique_ptr does not cause UB

2021-09-22 Thread Antony Polukhin via Gcc-patches
ср, 22 сент. 2021 г. в 20:44, Jonathan Wakely :
>
> On Wed, 22 Sept 2021 at 18:09, Antony Polukhin wrote:
> >
> > std::unique_ptr allows construction from std::unique_ptr of derived
> > type as per [unique.ptr.single.asgn] and [unique.ptr.single.ctor]. If
> > std::default_delete is used with std::unique_ptr, then after such
> > construction a delete is called on a pointer to base. According to
> > [expr.delete] calling a delete on a non similar object without a
> > virtual destructor is an undefined behavior.
> >
> > This patch turns that undefined behavior into static assertions inside
> > std::unique_ptr.
>
> The undefined behaviour only happens if the destructor is actually
> reached at runtime, but won't these static assertions make it
> ill-formed to instantiate these members, even if the UB never happens?
>
> For example, if you ensure that release() is called before
> destruction, the undefined delete never happens.

Ugh... I've missed that use case. Patch is just wrong, discard it

-- 
Best regards,
Antony Polukhin


Re: [PATCH] assert that deleting by pointer to base in unique_ptr does not cause UB

2021-09-22 Thread Antony Polukhin via Gcc-patches
ср, 22 сент. 2021 г. в 20:23, Ville Voutilainen :
>
> On Wed, 22 Sept 2021 at 20:09, Antony Polukhin via Libstdc++
>  wrote:
> >
> > std::unique_ptr allows construction from std::unique_ptr of derived
> > type as per [unique.ptr.single.asgn] and [unique.ptr.single.ctor]. If
> > std::default_delete is used with std::unique_ptr, then after such
> > construction a delete is called on a pointer to base. According to
> > [expr.delete] calling a delete on a non similar object without a
> > virtual destructor is an undefined behavior.
> >
> > This patch turns that undefined behavior into static assertions inside
> > std::unique_ptr.
>
> I don't understand the sizeof(_Tp) == sizeof(_Up) part in the
> static_assert. I fail to see how
> a same-size check suggests that the types are similar enough that a
> delete-expression works.

I used the following logic:
[unique.ptr.single.*] sections have the constraint that
"unique_­ptr::pointer is implicitly convertible to pointer".
There's already a static assert that T in unique_ptr is not void,
so U either has to be the same type T, or a type derived from T. If a
derived type adds members, then size changes and types are not similar
as the decompositions won't have the qualification-decompositions with
the same n.

-- 
Best regards,
Antony Polukhin


[PATCH] assert that deleting by pointer to base in unique_ptr does not cause UB

2021-09-22 Thread Antony Polukhin via Gcc-patches
std::unique_ptr allows construction from std::unique_ptr of derived
type as per [unique.ptr.single.asgn] and [unique.ptr.single.ctor]. If
std::default_delete is used with std::unique_ptr, then after such
construction a delete is called on a pointer to base. According to
[expr.delete] calling a delete on a non similar object without a
virtual destructor is an undefined behavior.

This patch turns that undefined behavior into static assertions inside
std::unique_ptr.

Changelog:
* include/bits/unique_ptr.h: Add static asserts that
deleting by pointer to base in unique_ptr does not cause UB
* testsuite/20_util/unique_ptr/assign/slicing_neg.cc:
New test.


-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/bits/unique_ptr.h 
b/libstdc++-v3/include/bits/unique_ptr.h
index 6e55375..53a68f5 100644
--- a/libstdc++-v3/include/bits/unique_ptr.h
+++ b/libstdc++-v3/include/bits/unique_ptr.h
@@ -339,7 +339,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
is_convertible<_Ep, _Dp>>::type>>
unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
-   { }
+   {
+ static_assert(!is_same<_Dp, default_delete<_Tp>>::value
+   || has_virtual_destructor::type>::value
+   || sizeof(_Tp) == sizeof(_Up),
+   "type of pointer owned by __u must be similar to the type of 
pointer "
+   "owned by this object or the latter must have a virtual 
destructor");
+   }
 
 #if _GLIBCXX_USE_DEPRECATED
 #pragma GCC diagnostic push
@@ -385,6 +391,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   unique_ptr&>::type
operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
{
+ static_assert(!is_same<_Dp, default_delete<_Tp>>::value
+   || has_virtual_destructor::type>::value
+   || sizeof(_Tp) == sizeof(_Up),
+   "type of pointer owned by __u must be similar to the type of 
pointer "
+   "owned by this object or the latter must have a virtual 
destructor");
+
  reset(__u.release());
  get_deleter() = std::forward<_Ep>(__u.get_deleter());
  return *this;
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/slicing_neg.cc 
b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/slicing_neg.cc
new file mode 100644
index 000..e93483a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/slicing_neg.cc
@@ -0,0 +1,86 @@
+// { dg-do compile { target c++11 } }
+// { dg-prune-output "virtual destructor" }
+
+// Copyright (C) 2021 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
+// .
+
+#include 
+
+struct A { };
+struct B : A { };
+struct C : B { int i; };
+
+struct Ac { char c; };
+struct Bc : Ac { };
+struct Cc : Bc { short s; };
+
+
+void test01()
+{
+  std::unique_ptr upB;
+
+  std::unique_ptr cA;
+  cA = std::move(upB);
+
+  std::unique_ptr vA;
+  vA = std::move(upB);
+
+  std::unique_ptr cvA;
+  cvA = std::move(upB);
+}
+
+void test02()
+{
+  std::unique_ptr upC;
+
+  std::unique_ptr cA{std::move(upC)};  // { dg-error "required from 
here" }
+  cA = std::move(upC);  // { dg-error "required from here" }
+
+  std::unique_ptr vA{std::move(upC)};  // { dg-error "required 
from here" }
+  vA = std::move(upC);  // { dg-error "required from here" }
+
+  std::unique_ptr cvA{std::move(upC)};  // { dg-error 
"required from here" }
+  cvA = std::move(upC);  // { dg-error "required from here" }
+}
+
+void test03()
+{
+  std::unique_ptr upB;
+
+  std::unique_ptr cA;
+  cA = std::move(upB);
+
+  std::unique_ptr vA;
+  vA = std::move(upB);
+
+  std::unique_ptr cvA;
+  cvA = std::move(upB);
+}
+
+void test04()
+{
+  std::unique_ptr upC;
+
+  std::unique_ptr cA{std::move(upC)};  // { dg-error "required from 
here" }
+  cA = std::move(upC);  // { dg-error "required from here" }
+
+  std::unique_ptr vA{std::move(upC)};  // { dg-error "required 
from here" }
+  vA = std::move(upC);  // { dg-error "required from here" }
+
+  std::unique_ptr cvA{std::move(upC)};  // { dg-error 
"required from here" }
+  cvA = std::move(upC);  // { dg-error "required from here" }
+}


Re: [PATCH] Optimize seed_seq construction

2021-08-17 Thread Antony Polukhin via Gcc-patches
вт, 17 авг. 2021 г. в 16:37, Jonathan Wakely :
<...>
> Thanks, this is a nice improvement. We can avoid tag dispatching to
> make it simpler though:
>
> @@ -3248,6 +3249,9 @@ namespace __detail
>   template
> seed_seq::seed_seq(_InputIterator __begin, _InputIterator __end)
> {
> +  if _GLIBCXX17_CONSTEXPR
> (__is_random_access_iter<_InputIterator>::value)
> +   _M_v.reserve(std::distance(__begin, __end));
> +
>   for (_InputIterator __iter = __begin; __iter != __end; ++__iter)
>_M_v.push_back(__detail::__mod   __detail::_Shift::__value>(*__iter));
>
> The call to std::distance is well-formed for input iterators, but we
> won't actually call it unless we have random access iterators.
>
> Unless you see a problem with this that I'm missing, I'll go with that 
> version.

Looks much better. Thanks!

-- 
Best regards,
Antony Polukhin


[PATCH] Optimize seed_seq construction

2021-08-17 Thread Antony Polukhin via Gcc-patches
When std::seed_seq is constructed from random access iterators we can
detect the internal vector size in O(1). Reserving memory for elements
in such cases may avoid multiple memory allocations.

libstdc++-v3/ChangeLog:

* include/bits/random.tcc: Optimize seed_seq construction.

-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/bits/random.tcc 
b/libstdc++-v3/include/bits/random.tcc
index bf43970..816bfc1 100644
--- a/libstdc++-v3/include/bits/random.tcc
+++ b/libstdc++-v3/include/bits/random.tcc
@@ -3234,14 +3234,31 @@ namespace __detail
   template
 seed_seq::seed_seq(std::initializer_list<_IntType> __il)
 {
+  _M_v.reserve(__il.size());
   for (auto __iter = __il.begin(); __iter != __il.end(); ++__iter)
_M_v.push_back(__detail::__mod::__value>(*__iter));
 }
 
+  template
+void __reserve_if_distance_cheap(_Vector& __vec, _InputIterator __begin,
+  _InputIterator __end, random_access_iterator_tag)
+{
+  __vec.reserve(__end - __begin);
+}
+
+  template
+void __reserve_if_distance_cheap(_Vector&, _InputIterator,
+  _InputIterator, _Tag)
+{
+  // computing the distance between __begin and __end is not O(1)
+}
+
   template
 seed_seq::seed_seq(_InputIterator __begin, _InputIterator __end)
 {
+  std::__reserve_if_distance_cheap(_M_v, __begin, __end,
+  typename iterator_traits<_InputIterator>::iterator_category());
   for (_InputIterator __iter = __begin; __iter != __end; ++__iter)
_M_v.push_back(__detail::__mod::__value>(*__iter));


Re: [PATCH] PR libstdc++/89728 diagnose some missuses of [locale.convenience] functions

2021-05-12 Thread Antony Polukhin via Gcc-patches
ср, 12 мая 2021 г. в 18:38, Antony Polukhin :
>
> ср, 12 мая 2021 г. в 17:44, Jonathan Wakely :
> >
> > On 12/05/21 12:58 +0300, Antony Polukhin wrote:
> > >ср, 12 мая 2021 г. в 12:18, Jonathan Wakely :
> > ><...>
> > >> Or just leave it undefined, as libc++ seems to do according to your
> > >> comment in PR 89728:
> > >>
> > >> error: implicit instantiation of undefined template 
> > >> 'std::__1::ctype >'
> > >>
> > >> Was your aim to have a static_assert that gives a more descriptive
> > >> error? We could leave it undefined in C++98 and have the static assert
> > >> for C++11 and up.
> > >
> > >Leaving it undefined would be the best. It would allow SFINAE on ctype
> > >and a compile time error is informative enough.
> > >
> > >However, there may be users who instantiate ctype in a
> > >shared library without ctype template specializations in
> > >the main executable. Making the default ctype undefined would break
> > >their compilation:
> > >
> > >#include 
> > >// no ctype specialization
> > >c = std::tolower(ThierChar{42}, locale_from_shared_library()); // OK
> > >right now in libstdc++, fails on libc++
> >
> > What I meant was leaving the partial specialization undefined, not the
> > primary template, i.e.
> >
> > --- a/libstdc++-v3/include/bits/locale_facets.h
> > +++ b/libstdc++-v3/include/bits/locale_facets.h
> > @@ -1476,6 +1476,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >   };
> >   #endif //_GLIBCXX_USE_WCHAR_T
> >
> > +  template
> > +class ctype >;
> > +
> > /// class ctype_byname [22.2.1.2].
> > template
> >   class ctype_byname : public ctype<_CharT>
> >
> > This makes your test fail with errors like this:
> >
> > In file included from /home/jwakely/gcc/12/include/c++/12.0.0/locale:40,
> >   from loc.C:1:
> > /home/jwakely/gcc/12/include/c++/12.0.0/bits/locale_facets.h: In 
> > instantiation of 'bool std::isspace(_CharT, const std::locale&) [with 
> > _CharT = std::__cxx11::basic_string]':
> > loc.C:16:15:   required from here
> > /home/jwakely/gcc/12/include/c++/12.0.0/bits/locale_facets.h:2600:47: 
> > error: invalid use of incomplete type 'const class 
> > std::ctype >'
> >   2600 | { return use_facet 
> > >(__loc).is(ctype_base::space, __c); }
> >|  ~^~
> >
> > But it shouldn't affect the uses of ctype.
> >
> > What do you think?
>
> Good idea. That way the compiler message points directly to the
> misused function.
>
> Patch is in attachment

Replaced {} with () in test to be C++98 compatible


-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/bits/locale_facets.h 
b/libstdc++-v3/include/bits/locale_facets.h
index 03724cf..5ca431e 100644
--- a/libstdc++-v3/include/bits/locale_facets.h
+++ b/libstdc++-v3/include/bits/locale_facets.h
@@ -671,6 +671,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 locale::id ctype<_CharT>::id;
 
+  // Incomplete to provide a compile time diagnostics for common misuse
+  // of [locale.convenience] functions with basic_string as a character type.
+  template
+class ctype >;
+
   /**
*  @brief  The ctype specialization.
*  @ingroup locales
diff --git a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc 
b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
new file mode 100644
index 000..9f15620
--- /dev/null
+++ b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
@@ -0,0 +1,73 @@
+// { dg-do compile }
+
+// Copyright (C) 2021 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
+// .
+
+// { dg-error "complete" "" { target *-*-* } 0 }
+
+#include 
+
+template 
+struct trait: std::char_traits {};
+
+template 
+std::basic_string > make_str()
+{
+  return std::basic_string >();
+}
+
+void test01()
+{
+  const std::locale& loc = std::locale::classic();
+
+  std::isspace(std::string(), loc);// { dg-error "required from 
here" }
+  std::isprint(make_str(), loc);  // { dg-error "required from 
here" }
+  std::iscntrl(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isupper(make_str(), loc);  // { dg-error "required from 
here" }
+  std::islower(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isalpha(make_str(), loc);  // { dg-error "required from 
here" }
+  

Re: [PATCH] PR libstdc++/89728 diagnose some missuses of [locale.convenience] functions

2021-05-12 Thread Antony Polukhin via Gcc-patches
ср, 12 мая 2021 г. в 17:44, Jonathan Wakely :
>
> On 12/05/21 12:58 +0300, Antony Polukhin wrote:
> >ср, 12 мая 2021 г. в 12:18, Jonathan Wakely :
> ><...>
> >> Or just leave it undefined, as libc++ seems to do according to your
> >> comment in PR 89728:
> >>
> >> error: implicit instantiation of undefined template 
> >> 'std::__1::ctype >'
> >>
> >> Was your aim to have a static_assert that gives a more descriptive
> >> error? We could leave it undefined in C++98 and have the static assert
> >> for C++11 and up.
> >
> >Leaving it undefined would be the best. It would allow SFINAE on ctype
> >and a compile time error is informative enough.
> >
> >However, there may be users who instantiate ctype in a
> >shared library without ctype template specializations in
> >the main executable. Making the default ctype undefined would break
> >their compilation:
> >
> >#include 
> >// no ctype specialization
> >c = std::tolower(ThierChar{42}, locale_from_shared_library()); // OK
> >right now in libstdc++, fails on libc++
>
> What I meant was leaving the partial specialization undefined, not the
> primary template, i.e.
>
> --- a/libstdc++-v3/include/bits/locale_facets.h
> +++ b/libstdc++-v3/include/bits/locale_facets.h
> @@ -1476,6 +1476,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>   };
>   #endif //_GLIBCXX_USE_WCHAR_T
>
> +  template
> +class ctype >;
> +
> /// class ctype_byname [22.2.1.2].
> template
>   class ctype_byname : public ctype<_CharT>
>
> This makes your test fail with errors like this:
>
> In file included from /home/jwakely/gcc/12/include/c++/12.0.0/locale:40,
>   from loc.C:1:
> /home/jwakely/gcc/12/include/c++/12.0.0/bits/locale_facets.h: In 
> instantiation of 'bool std::isspace(_CharT, const std::locale&) [with _CharT 
> = std::__cxx11::basic_string]':
> loc.C:16:15:   required from here
> /home/jwakely/gcc/12/include/c++/12.0.0/bits/locale_facets.h:2600:47: error: 
> invalid use of incomplete type 'const class 
> std::ctype >'
>   2600 | { return use_facet >(__loc).is(ctype_base::space, 
> __c); }
>|  ~^~
>
> But it shouldn't affect the uses of ctype.
>
> What do you think?

Good idea. That way the compiler message points directly to the
misused function.

Patch is in attachment

-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/bits/locale_facets.h 
b/libstdc++-v3/include/bits/locale_facets.h
index 03724cf..5ca431e 100644
--- a/libstdc++-v3/include/bits/locale_facets.h
+++ b/libstdc++-v3/include/bits/locale_facets.h
@@ -671,6 +671,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 locale::id ctype<_CharT>::id;
 
+  // Incomplete to provide a compile time diagnostics for common misuse
+  // of [locale.convenience] functions with basic_string as a character type.
+  template
+class ctype >;
+
   /**
*  @brief  The ctype specialization.
*  @ingroup locales
diff --git a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc 
b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
new file mode 100644
index 000..ccab3a2
--- /dev/null
+++ b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
@@ -0,0 +1,73 @@
+// { dg-do compile }
+
+// Copyright (C) 2021 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
+// .
+
+// { dg-error "complete" "" { target *-*-* } 0 }
+
+#include 
+
+template 
+struct trait: std::char_traits {};
+
+template 
+std::basic_string > make_str()
+{
+  return std::basic_string >();
+}
+
+void test01()
+{
+  const std::locale& loc = std::locale::classic();
+
+  std::isspace(std::string{}, loc);// { dg-error "required from 
here" }
+  std::isprint(make_str(), loc);  // { dg-error "required from 
here" }
+  std::iscntrl(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isupper(make_str(), loc);  // { dg-error "required from 
here" }
+  std::islower(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isalpha(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isdigit(make_str(), loc);  // { dg-error "required from 
here" }
+  std::ispunct(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isxdigit(make_str(), loc); // { dg-error "required from 
here" }
+  

Re: [PATCH] PR libstdc++/89728 diagnose some missuses of [locale.convenience] functions

2021-05-12 Thread Antony Polukhin via Gcc-patches
ср, 12 мая 2021 г. в 12:58, Antony Polukhin :
<...>
> Should we care about those users?

Looks like the answer is "yes". There are tests for that in
22_locale/ctype/requirements/explicit_instantiation.cc and
22_locale/money_get/cons/3.cc

Attaching a patch with review fixes (with ctype specialization for basic_string)

-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/bits/locale_facets.h 
b/libstdc++-v3/include/bits/locale_facets.h
index 03724cf..bbd7da5 100644
--- a/libstdc++-v3/include/bits/locale_facets.h
+++ b/libstdc++-v3/include/bits/locale_facets.h
@@ -671,6 +671,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 locale::id ctype<_CharT>::id;
 
+  // Compile time diagnostics for common misuse of [locale.convenience]
+  // functions with basic_string as a character type.
+  template
+class ctype >
+{
+#if __cplusplus >= 201103L
+  static_assert(sizeof(_CharT) && false,
+   "std::basic_string used as a character type");
+#endif
+  ctype();
+  ~ctype();
+};
+
   /**
*  @brief  The ctype specialization.
*  @ingroup locales
diff --git a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc 
b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
new file mode 100644
index 000..268e03a
--- /dev/null
+++ b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
@@ -0,0 +1,75 @@
+// { dg-do compile }
+
+// Copyright (C) 2021 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
+// .
+
+// { dg-error "basic_string used as a character type" "" { target c++11 } 0 }
+// { dg-error "is not a member of" "" { target *-*-* } 0 }
+// { dg-error "has no member named" "" { target *-*-* } 0 }
+
+#include 
+
+template 
+struct trait: std::char_traits {};
+
+template 
+std::basic_string > make_str()
+{
+  return std::basic_string >();
+}
+
+void test01()
+{
+  const std::locale& loc = std::locale::classic();
+
+  std::isspace(std::string{}, loc);// { dg-error "required from 
here" }
+  std::isprint(make_str(), loc);  // { dg-error "required from 
here" }
+  std::iscntrl(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isupper(make_str(), loc);  // { dg-error "required from 
here" }
+  std::islower(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isalpha(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isdigit(make_str(), loc);  // { dg-error "required from 
here" }
+  std::ispunct(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isxdigit(make_str(), loc); // { dg-error "required from 
here" }
+  std::isalnum(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isgraph(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isblank(make_str(), loc); // { dg-error "required from 
here" }
+  std::toupper(make_str(), loc); // { dg-error "required from 
here" }
+  std::tolower(make_str(), loc); // { dg-error "required from 
here" }
+}
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+void test02()
+{
+  const std::locale& loc = std::locale::classic();
+
+  std::isspace(std::wstring{}, loc);   // { dg-error "required from 
here" }
+  std::isprint(make_str(), loc);   // { dg-error "required from 
here" }
+  std::iscntrl(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isupper(make_str(), loc);   // { dg-error "required from 
here" }
+  std::islower(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isalpha(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isdigit(make_str(), loc);   // { dg-error "required from 
here" }
+  std::ispunct(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isxdigit(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isalnum(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isgraph(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isblank(make_str(), loc);  // { dg-error "required from 
here" }
+  std::toupper(make_str(), loc);  // { dg-error "required from 
here" }
+  std::tolower(make_str(), loc);  // { dg-error "required from 
here" }
+}
+#endif


Re: [PATCH] PR libstdc++/89728 diagnose some missuses of [locale.convenience] functions

2021-05-12 Thread Antony Polukhin via Gcc-patches
ср, 12 мая 2021 г. в 12:18, Jonathan Wakely :
<...>
> Or just leave it undefined, as libc++ seems to do according to your
> comment in PR 89728:
>
> error: implicit instantiation of undefined template 
> 'std::__1::ctype >'
>
> Was your aim to have a static_assert that gives a more descriptive
> error? We could leave it undefined in C++98 and have the static assert
> for C++11 and up.

Leaving it undefined would be the best. It would allow SFINAE on ctype
and a compile time error is informative enough.

However, there may be users who instantiate ctype in a
shared library without ctype template specializations in
the main executable. Making the default ctype undefined would break
their compilation:

#include 
// no ctype specialization
c = std::tolower(ThierChar{42}, locale_from_shared_library()); // OK
right now in libstdc++, fails on libc++


Should we care about those users?

-- 
Best regards,
Antony Polukhin


[PATCH] PR libstdc++/89728 diagnose some missuses of [locale.convenience] functions

2021-05-11 Thread Antony Polukhin via Gcc-patches
This patch provides compile time diagnostics for common misuse of
[locale.convenience] functions with std::string as a character type.


2021-05-11  Antony Polukhin  

PR libstdc++/89728
  * include/bits/locale_facets.h (ctype) Add static assert.
  * testsuite/22_locale/ctype/is/string/89728_neg.cc New test.

-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/bits/locale_facets.h 
b/libstdc++-v3/include/bits/locale_facets.h
index 03724cf..012857f 100644
--- a/libstdc++-v3/include/bits/locale_facets.h
+++ b/libstdc++-v3/include/bits/locale_facets.h
@@ -136,6 +136,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   return __s;
 }
 
+  template
+struct __is_string
+{
+   enum _Value { _value = 0 };
+};
+
+  template
+struct __is_string >
+{
+   enum _Value { _value = 1 };
+};
 
   // 22.2.1.1  Template class ctype
   // Include host and configuration specific ctype enums for ctype_base.
@@ -614,6 +625,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 class ctype : public __ctype_abstract_base<_CharT>
 {
+#if __cplusplus >= 201103L
+  static_assert(!__is_string<_CharT>::_value,
+   "std::basic_string used as a character type");
+#endif
 public:
   // Types:
   typedef _CharT   char_type;
diff --git a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc 
b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
new file mode 100644
index 000..987fa8e
--- /dev/null
+++ b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
@@ -0,0 +1,73 @@
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2021 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
+// .
+
+// { dg-error "used as a character type" "" { target *-*-* } 0 }
+
+#include 
+
+template 
+struct trait: std::char_traits {};
+
+template 
+auto make_str()
+{
+  return std::basic_string>{};
+}
+
+void test01()
+{
+  const auto& loc = std::locale::classic();
+
+  std::isspace(std::string{}, loc);// { dg-error "required from 
here" }
+  std::isprint(make_str(), loc);  // { dg-error "required from 
here" }
+  std::iscntrl(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isupper(make_str(), loc);  // { dg-error "required from 
here" }
+  std::islower(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isalpha(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isdigit(make_str(), loc);  // { dg-error "required from 
here" }
+  std::ispunct(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isxdigit(make_str(), loc); // { dg-error "required from 
here" }
+  std::isalnum(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isgraph(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isblank(make_str(), loc); // { dg-error "required from 
here" }
+  std::toupper(make_str(), loc); // { dg-error "required from 
here" }
+  std::tolower(make_str(), loc); // { dg-error "required from 
here" }
+}
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+void test02()
+{
+  const auto& loc = std::locale::classic();
+
+  std::isspace(std::wstring{}, loc);   // { dg-error "required from 
here" }
+  std::isprint(make_str(), loc);   // { dg-error "required from 
here" }
+  std::iscntrl(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isupper(make_str(), loc);   // { dg-error "required from 
here" }
+  std::islower(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isalpha(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isdigit(make_str(), loc);   // { dg-error "required from 
here" }
+  std::ispunct(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isxdigit(make_str(), loc);  // { dg-error "required from 
here" }
+  std::isalnum(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isgraph(make_str(), loc);   // { dg-error "required from 
here" }
+  std::isblank(make_str(), loc);  // { dg-error "required from 
here" }
+  std::toupper(make_str(), loc);  // { dg-error "required from 
here" }
+  std::tolower(make_str(), loc);  // { dg-error "required from 
here" }
+}
+#endif


Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type

2021-05-07 Thread Antony Polukhin via Gcc-patches
Rebased the patch on current master. Please review.

Changelog stays the same:

New std::common_type assertions attempt to give a proper 'required from
here' hint for user code, do not bring many changes to the
implementation and check all the template parameters for completeness.
In some cases the type could be checked for completeness more than
once. This seems to be unsolvable due to the fact that
std::common_type could be specialized by the user, so we have to call
std::common_type recursively, potentially repeating the check for the
first type.

std::common_reference assertions make sure that we detect incomplete
types even if the user specialized the std::basic_common_reference.

2020-11-12  Antony Polukhin  
PR libstdc/71579
* include/std/type_traits (is_convertible, is_nothrow_convertible)
(common_type, common_reference): Add static_asserts
to make sure that the arguments of the type traits are not misused
with incomplete types.
* testsuite/20_util/common_reference/incomplete_basic_common_neg.cc:
New test.
* testsuite/20_util/common_reference/incomplete_neg.cc: New test.
* testsuite/20_util/common_type/incomplete_neg.cc: New test.
* testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc: Remove
SFINAE tests on incomplete types.
* testsuite/20_util/is_convertible/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc: New test.

пт, 8 янв. 2021 г. в 20:28, Antony Polukhin :
>
>
> On Thu, Nov 12, 2020, 21:55 Antony Polukhin  wrote:
>>
>> Final bits for libstdc/71579
>
>
> Gentle reminder on last patch



-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index eaf06fc..a95d327 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1406,12 +1406,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 struct is_convertible
 : public __is_convertible_helper<_From, _To>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+   "first template argument must be a complete class or an unbounded 
array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+   "second template argument must be a complete class or an unbounded 
array");
+};
 
   // helper trait for unique_ptr, shared_ptr, and span
   template
 using __is_array_convertible
-  = is_convertible<_FromElementType(*)[], _ToElementType(*)[]>;
+  = typename __is_convertible_helper<
+   _FromElementType(*)[], _ToElementType(*)[]>::type;
 
   template, is_function<_To>,
@@ -1454,7 +1460,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 struct is_nothrow_convertible
 : public __is_nt_convertible_helper<_From, _To>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+   "first template argument must be a complete class or an unbounded 
array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+   "second template argument must be a complete class or an unbounded 
array");
+};
 
   /// is_nothrow_convertible_v
   template
@@ -2239,7 +2250,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 struct common_type<_Tp1, _Tp2>
 : public __common_type_impl<_Tp1, _Tp2>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+   "each argument type must be a complete class or an unbounded array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+   "each argument type must be a complete class or an unbounded array");
+};
 
   template
 struct __common_type_pack
@@ -2253,7 +2269,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 struct common_type<_Tp1, _Tp2, _Rp...>
 : public __common_type_fold,
__common_type_pack<_Rp...>>
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+   "first argument type must be a complete class or an unbounded array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+   "second argument type must be a complete class or an unbounded array");
+#ifdef __cpp_fold_expressions
+  static_assert((std::__is_complete_or_unbounded(
+   __type_identity<_Rp>{}) && ...),
+   "each argument type must be a complete class or an unbounded array");
+#endif
+};
 
   // Let C denote the same type, if any, as common_type_t.
   // If there is such a type C, type shall denote the same type, if any,
@@ -3352,9 +3378,10 @@ template 
 
   // If A and B are both rvalue reference types, ...
   template
-struct __common_ref_impl<_Xp&&, _Yp&&,
-  _Require>,
-  is_convertible<_Yp&&, __common_ref_C<_Xp, _Yp
+struct __common_ref_impl<_Xp&&, _Yp&&, _Require<
+  typename __is_convertible_helper<_Xp&&, 

Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type

2021-01-08 Thread Antony Polukhin via Gcc-patches
On Thu, Nov 12, 2020, 21:55 Antony Polukhin  wrote:

> Final bits for libstdc/71579
>

Gentle reminder on last patch

>


Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type

2020-11-12 Thread Antony Polukhin via Gcc-patches
Final bits for libstdc/71579

std::common_type assertions attempt to give a proper 'required from
here' hint for user code, do not bring many changes to the
implementation and check all the template parameters for completeness.
In some cases the type could be checked for completeness more than
once. This seems to be unsolvable due to the fact that
std::common_type could be specialized by the user, so we have to call
std::common_type recursively, potentially repeating the check for the
first type.

std::common_reference assertions make sure that we detect incomplete
types even if the user specialized the std::basic_common_reference.

Changelog:

2020-11-12  Antony Polukhin  
PR libstdc/71579
* include/std/type_traits (is_convertible, is_nothrow_convertible)
(common_type, common_reference): Add static_asserts
to make sure that the arguments of the type traits are not misused
with incomplete types.
* testsuite/20_util/common_reference/incomplete_basic_common_neg.cc:
New test.
* testsuite/20_util/common_reference/incomplete_neg.cc: New test.
* testsuite/20_util/common_type/incomplete_neg.cc: New test.
* testsuite/20_util/common_type/requirements/sfinae_friendly_1.cc: Remove
SFINAE tests on incomplete types.
* testsuite/20_util/is_convertible/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_convertible/incomplete_neg.cc: New test.



--
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index 34e068b..00fa7f5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1406,12 +1406,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 struct is_convertible
 : public __is_convertible_helper<_From, _To>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+   "first template argument must be a complete class or an unbounded 
array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+   "second template argument must be a complete class or an unbounded 
array");
+};
 
   // helper trait for unique_ptr, shared_ptr, and span
   template
 using __is_array_convertible
-  = is_convertible<_FromElementType(*)[], _ToElementType(*)[]>;
+  = typename __is_convertible_helper<
+   _FromElementType(*)[], _ToElementType(*)[]>::type;
 
   template, is_function<_To>,
@@ -1454,7 +1460,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 struct is_nothrow_convertible
 : public __is_nt_convertible_helper<_From, _To>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_From>{}),
+   "first template argument must be a complete class or an unbounded 
array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_To>{}),
+   "second template argument must be a complete class or an unbounded 
array");
+};
 
   /// is_nothrow_convertible_v
   template
@@ -2239,7 +2250,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 struct common_type<_Tp1, _Tp2>
 : public __common_type_impl<_Tp1, _Tp2>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+   "each argument type must be a complete class or an unbounded array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+   "each argument type must be a complete class or an unbounded array");
+};
 
   template
 struct __common_type_pack
@@ -2253,7 +2269,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 struct common_type<_Tp1, _Tp2, _Rp...>
 : public __common_type_fold,
__common_type_pack<_Rp...>>
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp1>{}),
+   "first argument type must be a complete class or an unbounded array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp2>{}),
+   "second argument type must be a complete class or an unbounded array");
+#ifdef __cpp_fold_expressions
+  static_assert((std::__is_complete_or_unbounded(
+   __type_identity<_Rp>{}) && ...),
+   "each argument type must be a complete class or an unbounded array");
+#endif
+};
 
   // Let C denote the same type, if any, as common_type_t.
   // If there is such a type C, type shall denote the same type, if any,
@@ -3315,9 +3341,10 @@ template 
 
   // If A and B are both rvalue reference types, ...
   template
-struct __common_ref_impl<_Xp&&, _Yp&&,
-  _Require>,
-  is_convertible<_Yp&&, __common_ref_C<_Xp, _Yp
+struct __common_ref_impl<_Xp&&, _Yp&&, _Require<
+  typename __is_convertible_helper<_Xp&&, __common_ref_C<_Xp, _Yp>>::type,
+  typename __is_convertible_helper<_Yp&&, __common_ref_C<_Xp, _Yp>>::type
+>>
 { using type = __common_ref_C<_Xp, _Yp>; };
 
   // let D be COMMON-REF(const X&, Y&)
@@ -3326,8 

Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type

2020-09-24 Thread Antony Polukhin via Gcc-patches
Looks like the last patch was not applied. Do I have to change something in
it?


Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type

2020-08-20 Thread Antony Polukhin via Gcc-patches
ср, 19 авг. 2020 г. в 14:29, Jonathan Wakely :
<...>
> Do we also want to check
> (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>{}) && ...)
> for invoke_result and the is_invocable traits?

Done.

Changelog:

2020-08-20  Antony Polukhin  

PR libstdc/71579
* include/std/type_traits (invoke_result, is_invocable, is_invocable_r)
(is_nothrow_invocable, is_nothrow_invocable_r): Add static_asserts
to make sure that the arguments of the type traits are not misused
with incomplete types.`
* testsuite/20_util/invoke_result/incomplete_args_neg.cc: New test.
* testsuite/20_util/is_invocable/incomplete_args_neg.cc: New test.
* testsuite/20_util/is_invocable/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_invocable/incomplete_args_neg.cc: New test.
* testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc: Check for
error on incomplete response type usage in trait.


-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index 6ced781..bf2260a 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2965,6 +2965,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 {
   
static_assert(std::__is_complete_or_unbounded(__type_identity<_Functor>{}),
"_Functor must be a complete class or an unbounded array");
+  static_assert((std::__is_complete_or_unbounded(
+   __type_identity<_ArgTypes>{}) && ...),
+   "Argument types must be a complete class or an unbounded array");
 };
 
   /// std::invoke_result_t
@@ -2978,6 +2981,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 {
   static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
"_Fn must be a complete class or an unbounded array");
+  static_assert((std::__is_complete_or_unbounded(
+   __type_identity<_ArgTypes>{}) && ...),
+   "Argument types must be a complete class or an unbounded array");
 };
 
   /// std::is_invocable_r
@@ -2987,6 +2993,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 {
   static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
"_Fn must be a complete class or an unbounded array");
+  static_assert((std::__is_complete_or_unbounded(
+   __type_identity<_ArgTypes>{}) && ...),
+   "Argument types must be a complete class or an unbounded array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Ret>{}),
+   "_Ret must be a complete class or an unbounded array");
 };
 
   /// std::is_nothrow_invocable
@@ -2997,6 +3008,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 {
   static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
"_Fn must be a complete class or an unbounded array");
+  static_assert((std::__is_complete_or_unbounded(
+   __type_identity<_ArgTypes>{}) && ...),
+   "Argument types must be a complete class or an unbounded array");
 };
 
   template
@@ -3017,6 +3031,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 {
   static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
"_Fn must be a complete class or an unbounded array");
+  static_assert((std::__is_complete_or_unbounded(
+   __type_identity<_ArgTypes>{}) && ...),
+   "Argument types must be a complete class or an unbounded array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Ret>{}),
+   "_Ret must be a complete class or an unbounded array");
 };
 
   /// std::is_invocable_v
diff --git 
a/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_args_neg.cc 
b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_args_neg.cc
new file mode 100644
index 000..a35ff4c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_args_neg.cc
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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
+// .
+
+// { dg-error "must be a complete class" "" { target *-*-* } 0 }
+
+#include 
+
+class X;
+
+void test01()
+{
+  std::invoke_result(); // { dg-error "required from 
here" }
+  std::invoke_result();   // { dg-error "required 
from here" }
+  std::invoke_result();   // { dg-error "required 
from here" 

Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type

2020-08-19 Thread Antony Polukhin via Gcc-patches
ср, 19 авг. 2020 г. в 14:29, Jonathan Wakely :
<...>
> Do we also want to check
> (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>{}) && ...)
> for invoke_result and the is_invocable traits?
>
> We can use a fold expression there, because those traits are not
> defined before C++17.

Good idea. I'll try.

-- 
Best regards,
Antony Polukhin


Re: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type

2020-08-12 Thread Antony Polukhin via Gcc-patches
Fixed patch for type traits hardening

Changelog

2020-08-12  Antony Polukhin  

PR libstdc/71579
* include/std/type_traits (invoke_result, is_nothrow_invocable_r)
Add static_asserts to make sure that the argument of the type
trait is not misused with incomplete types.
(is_swappable_with, is_nothrow_swappable_with): Add static_asserts
to make sure that the first and second arguments of the type trait
are not misused with incomplete types.
* testsuite/20_util/invoke_result/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc: New test.
* testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc: New
test.
* testsuite/20_util/is_swappable_with/incomplete_neg.cc: New test.


-- 
Best regards,
Antony Polukhin
diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index 426febc..62f1190 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2811,13 +2811,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 struct is_swappable_with
 : public __is_swappable_with_impl<_Tp, _Up>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+   "first template argument must be a complete class or an unbounded 
array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+   "second template argument must be a complete class or an unbounded 
array");
+};
 
   /// is_nothrow_swappable_with
   template
 struct is_nothrow_swappable_with
 : public __is_nothrow_swappable_with_impl<_Tp, _Up>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
+   "first template argument must be a complete class or an unbounded 
array");
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+   "second template argument must be a complete class or an unbounded 
array");
+};
 
 #if __cplusplus >= 201402L
   /// is_swappable_with_v
@@ -2952,7 +2962,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 struct invoke_result
 : public __invoke_result<_Functor, _ArgTypes...>
-{ };
+{
+  
static_assert(std::__is_complete_or_unbounded(__type_identity<_Functor>{}),
+   "_Functor must be a complete class or an unbounded array");
+};
 
   /// std::invoke_result_t
   template
@@ -3001,7 +3014,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 struct is_nothrow_invocable_r
 : __and_<__is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>,
  __call_is_nothrow_<_Fn, _ArgTypes...>>::type
-{ };
+{
+  static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
+   "_Fn must be a complete class or an unbounded array");
+};
 
   /// std::is_invocable_v
   template
diff --git a/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc 
b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc
new file mode 100644
index 000..da58a8b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/invoke_result/incomplete_neg.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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
+// .
+
+// { dg-error "must be a complete class" "" { target *-*-* } 0 }
+
+#include 
+
+class X;
+
+void test01()
+{
+  std::invoke_result();// { dg-error "required from 
here" }
+  std::invoke_result(); // { dg-error "required from here" }
+}
diff --git 
a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc 
b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
new file mode 100644
index 000..ad16809
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/incomplete_neg.cc
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++17 } }
+
+// Copyright (C) 2020 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