public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "eric.niebler at gmail dot com" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug c++/115378] New: [ice-on-valid] code using friend injection is crashing gcc since 14
Date: Thu, 06 Jun 2024 22:03:28 +0000	[thread overview]
Message-ID: <bug-115378-4@http.gcc.gnu.org/bugzilla/> (raw)

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115378

            Bug ID: 115378
           Summary: [ice-on-valid] code using friend injection is crashing
                    gcc since 14
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: eric.niebler at gmail dot com
  Target Milestone: ---

the following valid code crashes gcc-14 and gcc-trunk. clang accepts it, as
does gcc-13. see https://godbolt.org/z/s9frvq3Pv


#include <algorithm>
#include <cassert>
#include <concepts>
#include <functional>
#include <ranges>
#include <tuple>
#include <type_traits>

#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wunknown-warning-option"
#pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif

namespace std::execution {
  template <class Env, class Query, class... Args>
  concept __has_query =
    requires (const Env& __env, Args&&... __args) {
      __env.query(Query(), std::forward<Args>(__args)...);
    };

  // specialization for key/value pairs
  template <class Query, class Value>
  struct prop {
    [[no_unique_address]] Query __query;
    [[no_unique_address]] Value __value;

    [[nodiscard]] constexpr const Value & query(Query) const noexcept {
      return __value;
    }
  };

  template <class Query, class Value>
  prop(Query, Value) -> prop<Query, unwrap_reference_t<Value>>;

  template <class Env>
  struct __ref;

  template <class Env>
  struct __ref<Env&> {
    Env& __env;

    constexpr __ref(reference_wrapper<Env> __r) noexcept : __env(__r) {}

    template <class Query, class... Args>
      requires __has_query<Env, Query, Args...>
    constexpr decltype(auto) query(Query __q, Args&&... args) const
      noexcept(noexcept(__env.query(__q, std::forward<Args>(args)...))) {
      return __env.query(__q, std::forward<Args>(args)...);
    }
  };

  template<class Slot, size_t N>
  struct __reader {
    friend auto __counted_flag(__reader<Slot, N>);
  };

  template<class Slot, size_t N>
  struct __writer {
    friend auto __counted_flag(__reader<Slot, N>) {}
    static constexpr size_t __n = N;
  };

  template<class Slot, auto Tag, size_t NextVal = 0>
  consteval auto __counter_impl() {
    constexpr bool __counted_past_value = requires(__reader<Slot, NextVal> __r)
{
      __counted_flag(__r);
    };

    if constexpr (__counted_past_value) {
      return __counter_impl<Slot, Tag, NextVal + 1>();
    } else {
      return __writer<Slot, NextVal>().__n;
    }
  }

  template<class Slot, auto Tag = []{}, auto Val = __counter_impl<Slot, Tag>()>
  constexpr auto __counter = Val;

  template<class...> struct __list;

  template <class, size_t>
  struct __ignore {
    constexpr __ignore(auto&&) {}
    auto query(auto) const = delete;
  };

  template <class Env>
  using __wrap = conditional_t<is_reference_v<Env>, __ref<Env>, Env>;

  template <class Child, size_t Counter>
  using _as_base_ = conditional_t<Counter == 0, __wrap<Child>, __ignore<Child,
Counter>>;

  template <class Parent, class Child, size_t Counter =
__counter<__list<Parent, Child>>>
  using _as_base = _as_base_<Child, Counter>;

  // utility for joining multiple environments
  template <class... Envs>
  struct env : _as_base<env<Envs...>, Envs>... {
    template <class Query, class... Args>
    constexpr decltype(auto) __get_1st() const noexcept {
      constexpr bool __flags[] = {__has_query<Envs, Query, Args...>...};
      constexpr size_t __idx = ranges::find(__flags, true) - __flags;
      auto __tup = tie(static_cast<const __wrap<Envs>&>(*this)...);
      return get<__idx>(__tup);
    }

    template <class Query, class... Args>
      requires (__has_query<Envs, Query, Args...> ||...)
    constexpr decltype(auto) query(Query __q, Args&&... args) const
      noexcept(noexcept(__get_1st<Query, Args...>().query(__q,
std::forward<Args>(args)...))) {
      return __get_1st<Query, Args...>().query(__q,
std::forward<Args>(args)...);
    }
  };

  template <class... Envs>
  env(Envs...) -> env<unwrap_reference_t<Envs>...>;
} // std::execution

// Test code:
template <size_t>
struct get_value_t {
  auto operator()(const auto& env) const noexcept -> decltype(env.query(*this))
{
    static_assert(noexcept(env.query(*this)));
    return env.query(*this);
  }
};

template <size_t I>
inline constexpr get_value_t<I> get_value{};

int main() {
  using namespace std::execution;

  // can create an environment out of a query and a value
  auto env1 = prop(get_value<0>, 42);
  auto val = get_value<0>(env1);
  assert(val == 42);

  // can store a value by reference:
  int i = 42;
  auto env2 = prop(get_value<0>, std::ref(i));
  int& j = get_value<0>(env2);
  ++j;
  assert(i == 43);

  // Can create an env from several envs with duplicates.
  // Queries are resolved by asking the nested envs first to last.
  auto env3 = env(prop(get_value<0>, 42),
                  prop(get_value<1>, 43),
                  prop(get_value<1>, 44),
                  prop(get_value<0>, 45),
                  prop(get_value<0>, 46));
  assert(get_value<0>(env3) == 42);
  assert(get_value<1>(env3) == 43);

  // nested envs can be held by reference also:
  auto env4 = env(prop(get_value<1>, 42), std::cref(env2));
  assert(get_value<0>(env4) == 43);
  assert(get_value<1>(env4) == 42);
}

             reply	other threads:[~2024-06-06 22:03 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-06 22:03 eric.niebler at gmail dot com [this message]
2024-06-06 22:13 ` [Bug c++/115378] " pinskia at gcc dot gnu.org
2024-06-06 22:14 ` pinskia at gcc dot gnu.org
2024-06-06 22:34 ` pinskia at gcc dot gnu.org
2024-06-06 22:40 ` pinskia at gcc dot gnu.org
2024-06-06 22:42 ` [Bug c++/115378] [14/15 Regression] ICE with lambda function as a default template argument with variadic templates in some cases pinskia at gcc dot gnu.org
2024-06-07 13:49 ` ppalka at gcc dot gnu.org
2024-06-07 16:14 ` cvs-commit at gcc dot gnu.org
2024-06-10 14:16 ` cvs-commit at gcc dot gnu.org
2024-06-10 14:16 ` ppalka at gcc dot gnu.org

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=bug-115378-4@http.gcc.gnu.org/bugzilla/ \
    --to=gcc-bugzilla@gcc.gnu.org \
    --cc=gcc-bugs@gcc.gnu.org \
    /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).