public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/112307] New: Segmentation fault with -O1 -fcode-hoisting
@ 2023-10-31  9:39 raffael at casagrande dot ch
  2023-10-31  9:51 ` [Bug tree-optimization/112307] " rguenth at gcc dot gnu.org
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: raffael at casagrande dot ch @ 2023-10-31  9:39 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 112307
           Summary: Segmentation fault with -O1 -fcode-hoisting
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: raffael at casagrande dot ch
  Target Milestone: ---

*Affected Versions*: 10.0 - current (14.0.0 20231031). Earlier versions cannot
compile the code because it uses c++20.

*System*: Linux
*Command Line*: g++ main.cc -std=c++20 -O1 -fcode-hoisting

*Compiler Output*:

<source>:48:87: warning: friend declaration 'bool operator==(const
EnumeratorRange<ENUMERATOR>::Sentinel&, const
EnumeratorRange<ENUMERATOR>::Iterator&)' declares a non-template function
[-Wnon-template-friend]
   48 |     friend auto operator==(const Sentinel& /*unused*/, const Iterator&
i) noexcept -> bool;
      |                                                                        
              ^~~~
<source>:48:87: note: (if this is not what you intended, make sure the function
template has already been declared and add '<>' after the function name here)

*Runtime Output*: Segmentation fault, "boundary" is printed many times.


*Source File*:
#include <ranges>
#include <iostream>
#include <optional>
#include <cassert>



template <class ENUMERATOR>
class EnumeratorRange {
 public:
  struct Sentinel {
    Sentinel() noexcept = default;
    Sentinel(const Sentinel&) noexcept = default;
    Sentinel(Sentinel&&) noexcept = default;
    auto operator=(const Sentinel&) noexcept -> Sentinel& = default;
    auto operator=(Sentinel&&) noexcept -> Sentinel& = default;
    ~Sentinel() noexcept = default;
  };

  class Iterator {
   public:
    using value_type = typename ENUMERATOR::value_type;
    using difference_type = std::ptrdiff_t;
    explicit Iterator(EnumeratorRange* range) : range_(range) {}
    Iterator() noexcept = default;
    Iterator(const Iterator&) = delete;
    Iterator(Iterator&&) noexcept = default;
    ~Iterator() noexcept = default;
    auto operator=(const Iterator&) = delete;
    auto operator=(Iterator&&) noexcept -> Iterator& = default;

    auto operator*() const noexcept {
      assert(!range_->end_reached_);

      return *range_->enumerator_;
    }
    auto operator++() noexcept -> Iterator& {
      assert(!range_->end_reached_);
      range_->end_reached_ = !range_->enumerator_.Next();
      return *this;
    }

    auto operator++(int) noexcept -> void { ++*this; }

   private:
    EnumeratorRange* range_;

    friend auto operator==(const Sentinel& /*unused*/, const Iterator& i)
noexcept -> bool;
  };

  explicit EnumeratorRange(ENUMERATOR&& e)
      : enumerator_(std::move(e)), end_reached_(!enumerator_.Next()) {}

  auto begin() const noexcept {
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
    return Iterator(const_cast<EnumeratorRange*>(this));
  }

  auto end() const noexcept { return Sentinel(); }

 private:
  ENUMERATOR enumerator_;
  bool end_reached_;

  friend auto operator==(const Sentinel&, const Iterator& i) noexcept -> bool {
    return i.range_->end_reached_;
  }
  friend auto operator==(const Iterator& i, const Sentinel& s) noexcept -> bool
{ return s == i; }
  friend auto operator!=(const Sentinel& s, const Iterator& i) noexcept -> bool
{
    return !(s == i);
  }
  friend auto operator!=(const Iterator& i, const Sentinel& s) noexcept -> bool
{
    return !(s == i);
  }
};

class Intersection {
 public:

  auto Boundary() const noexcept -> bool { return is_boundary_; }

 private:
  bool is_boundary_ = true;
};


class CompositeMesh {
 public:

  auto Intersections() const noexcept -> std::ranges::input_range auto;

};


auto CompositeMesh::Intersections() const noexcept -> std::ranges::input_range
auto {
  class Enumerator {
   public:
    using wrapped_range_t = decltype(std::views::single(Intersection()));
    explicit Enumerator(wrapped_range_t&& range) : range_(std::move(range)),
begin_{} {}

    using value_type = Intersection;

    auto operator*() const noexcept -> value_type { return *begin_.value(); }

    auto Next() noexcept -> bool {
      if (!begin_.has_value()) {
        auto b = range_.begin();
        bool result = (b != range_.end());
        begin_ = std::move(b);
        return result;
      } else {
        auto& b = *begin_;
        if ((*b).Boundary()) {
          std::cout << "boundary" << std::endl;
        }

        ++b;
        return b != range_.end();
      }
    }

   private:
    wrapped_range_t range_;
    std::optional<std::ranges::iterator_t<wrapped_range_t>> begin_;
  };

  return EnumeratorRange(Enumerator(std::views::single(Intersection())));
}

int main() {
  auto mesh = CompositeMesh();

  decltype(auto) intersections = mesh.Intersections();
  for (auto intersection : intersections) {
  }
}

*Additional Notes*
- It works if we use `-O2` (which includes -fcode-hoisting)
- Godbolt: https://godbolt.org/z/1PqTKz33Y
- One can disable the following compiler options from `-O1` and still reproduce
the bug: -fno-auto-inc-dec -fno-branch-count-reg -fno-combine-stack-adjustments
-fno-compare-elim -fno-cprop-registers -fno-dce -fno-defer-pop
-fno-delayed-branch -fno-dse -fno-forward-propagate -fno-if-conversion
-fno-if-conversion2 -fno-inline-functions-called-once -fno-ipa-modref
-fno-ipa-profile -fno-ipa-pure-const -fno-ipa-reference
-fno-ipa-reference-addressable -fno-merge-constants -fno-move-loop-invariants
-fno-move-loop-stores -fno-omit-frame-pointer -fno-reorder-blocks
-fno-shrink-wrap -fno-shrink-wrap-separate -fno-split-wide-types
-fno-ssa-backprop -fno-ssa-phiopt -fno-tree-bit-ccp -fno-tree-ccp -fno-tree-ch
-fno-tree-coalesce-vars -fno-tree-copy-prop -fno-tree-dce
-fno-tree-dominator-opts -fno-tree-phiprop -fno-tree-scev-cprop -fno-tree-sink
-fno-tree-slsr -fno-tree-sra -fno-tree-ter -fno-unit-at-a-time

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2024-03-08 15:12 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-31  9:39 [Bug c++/112307] New: Segmentation fault with -O1 -fcode-hoisting raffael at casagrande dot ch
2023-10-31  9:51 ` [Bug tree-optimization/112307] " rguenth at gcc dot gnu.org
2023-10-31 10:21 ` rguenth at gcc dot gnu.org
2023-10-31 10:43 ` rguenth at gcc dot gnu.org
2024-03-05 11:34 ` rguenth at gcc dot gnu.org
2024-03-05 15:05 ` redi at gcc dot gnu.org
2024-03-05 15:37 ` rguenth at gcc dot gnu.org
2024-03-08 12:58 ` raffael at casagrande dot ch
2024-03-08 14:30 ` redi at gcc dot gnu.org
2024-03-08 14:32 ` redi at gcc dot gnu.org
2024-03-08 15:12 ` raffael at casagrande dot ch

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).