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

            Bug ID: 88816
           Summary: Constructor calls itself recursively
           Product: gcc
           Version: 8.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: isj-bugzilla at i1 dot dk
  Target Milestone: ---

In the reduced code below the constructor
Value::Value(std::vector<Value, std::allocator<Value> > const&)
calls itself in the generated code leading to stack overflow. There is no such
recursive call in the source code.
Bug produced with versions 7.3.1, 8.2.1. And "trunk" on godbolt.org.
Bug is absent with clang, mscv, and icc.

Optimization and debug levels are irrelevant. It just have so have -std=c++11
or later.

---snip---
#include <vector>

enum class value_type_t {
        array,
        null,
};

class Value {
        void clear() {
                switch(value_type) {
                        case value_type_t::array:
                                u.array_elements.~array_type();
                                break;
                        case value_type_t::null:
                                break;
                }
                value_type = value_type_t::null;
        }
public:
        using array_type = std::vector<Value>;

        value_type_t value_type;
        union U {
                U() {}
                ~U() {}
                array_type array_elements;
        } u;

        Value()
          : value_type{value_type_t::null}
        {}

        Value(const Value &v)
          : value_type{value_type_t::null}
        {
                *this = v;
        }

        //This is the constructor that unexpectedly calls itself
        Value(const array_type &a) {
                new(&u.array_elements) array_type{a};
                value_type = value_type_t::array;
        }

        ~Value() {
                clear();
        }


        Value& operator=(const Value &v) {
                if(this!=&v) {
                        clear();
                        switch(v.value_type) {
                                case value_type_t::array:
                                        new(&u.array_elements)
array_type{v.u.array_elements};
                                        value_type = value_type_t::array;
                                        return *this;
                                case value_type_t::null:
                                        value_type = value_type_t::null;
                                        break;
                        }
                }
                return *this;
        }

};


int main(void) {
        Value v{Value::array_type{}};
}
---snip---

Reply via email to