public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jonathan Wakely <jwakely@redhat.com>
To: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: gcc-patches List <gcc-patches@gcc.gnu.org>,
	libstdc++ <libstdc++@gcc.gnu.org>
Subject: Re: [PATCH] c++: Diagnose visitors with different return types for std::visit [PR95904]
Date: Tue, 29 Sep 2020 12:20:43 +0100	[thread overview]
Message-ID: <20200929112043.GL3946@redhat.com> (raw)
In-Reply-To: <CAFk2RUYGr0tU-1Qj2tLQQjOyR2JTuuo1vWFjO81sWbcyisRwug@mail.gmail.com>

On 29/09/20 01:12 +0300, Ville Voutilainen via Libstdc++ wrote:
>Not completely tested yet. This does fix the problem of converting
>incompatible pointer-to-function types, and thus gets rid of the suggestion
>that compiling the code with -fpermissive is a possibility. There
>is a special-casing for visit() for visitation of a single variant, and there
>we don't even instantiate the whole table mechanism. We should really
>entertain the possibility of flattening the whole visitation table; then
>this check could (at least in theory) be uniformly written as just
>an iteration of all table elements, which is not so convenient to do
>with the nested multitable. This seems like a worthy incremental
>improvement to me.
>
>2020-09-29  Ville Voutilainen  <ville.voutilainen@gmail.com>
>
>    PR libstdc++/95904
>    * include/std/variant (__same_types): New.
>    (__check_visitor_result): Likewise.
>    (__check_visitor_results): Likewise.
>    (visit(_Visitor&&, _Variants&&...)): Use __check_visitor_results
>    in case we're visiting just one variant.
>    (__gen_vtable_impl</*base case*/>::_S_apply):
>    Check the visitor return type.

>diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
>index dd8847cf829..56de78407c4 100644
>--- a/libstdc++-v3/include/std/variant
>+++ b/libstdc++-v3/include/std/variant
>@@ -182,7 +182,7 @@ namespace __variant
>   // used for raw visitation with indices passed in
>   struct __variant_idx_cookie { using type = __variant_idx_cookie; };
>   // Used to enable deduction (and same-type checking) for std::visit:
>-  template<typename> struct __deduce_visit_result { };
>+  template<typename _Tp> struct __deduce_visit_result { using type = _Tp; };
> 
>   // Visit variants that might be valueless.
>   template<typename _Visitor, typename... _Variants>
>@@ -1017,7 +1017,22 @@ namespace __variant
> 
>       static constexpr auto
>       _S_apply()
>-      { return _Array_type{&__visit_invoke}; }
>+      {
>+	constexpr bool __visit_ret_type_mismatch =
>+	  _Array_type::__result_is_deduced::value
>+	  && !is_same_v<typename _Result_type::type,
>+			decltype(__visit_invoke(std::declval<_Visitor>(),
>+						std::declval<_Variants>()...))>;
>+	if constexpr (__visit_ret_type_mismatch)
>+	  {
>+	    static_assert(!__visit_ret_type_mismatch,
>+			  "std::visit requires the visitor to have the same "
>+			  "return type for all alternatives of a variant");
>+	    return __nonesuch{};
>+	  }
>+	else
>+	  return _Array_type{&__visit_invoke};
>+      }
>     };
> 
>   template<typename _Result_type, typename _Visitor, typename... _Variants>
>@@ -1692,6 +1707,27 @@ namespace __variant
> 			   std::forward<_Variants>(__variants)...);
>     }
> 
>+  template <class _Tp, class... _Types>
>+    struct __same_types : public std::bool_constant<
>+    std::__and_<std::is_same<_Tp, _Types>...>::value> {};

This would be cheaper:

   template<typename _Tp, typename... _Types>
     using __same_types = typename __and_<is_same<_Tp, _Types>...>::type;

Although didn't we make changes in std::variant to stop using __and_
because it exceeds the template instantiation depth for large
variants?

I think this is what we want:

   template<typename _Tp, typename... _Types>
     constexpr inline __same_types = (is_same_v<_Tp, _Types> && ...);

is_same_v is very cheap, it uses the built-in directly, so you don't
need to instantiate any class templates at all.

>+
>+  template <unsigned long int _Idx, class _Visitor, class _Variant>

typename not class please.

>+    decltype(auto) __check_visitor_result(_Visitor&& __vis,

New line after the decltype(auto) please, not in the middle of the
parameter list.

I'll keep staring at this to review the actual content rather than the
window dressing that I've commented on above.


  reply	other threads:[~2020-09-29 11:20 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-28 22:12 Ville Voutilainen
2020-09-29 11:20 ` Jonathan Wakely [this message]
2020-09-29 16:35   ` [PATCH] libstdc++: Diagnose visitors with different return types [PR95904] Ville Voutilainen
2020-10-02 22:14     ` Jonathan Wakely
2020-10-04 22:15       ` Ville Voutilainen
2020-10-05 19:35         ` Ville Voutilainen
2020-10-08 14:27           ` Jonathan Wakely
2020-10-17 17:30             ` Stephan Bergmann
2020-10-17 17:36               ` Ville Voutilainen
2020-10-10 10:52           ` Jonathan Wakely
2020-10-10 11:15             ` Ville Voutilainen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200929112043.GL3946@redhat.com \
    --to=jwakely@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=libstdc++@gcc.gnu.org \
    --cc=ville.voutilainen@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).