On Fri, Aug 28, 2020 at 7:36 AM Yongwei Wu via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
...

struct StringIntChar {
    enum { String, Int, Char } type;
    ~StringIntChar()
    {
        if (type == String) {
            string_value.~string();
        }
    }
    union {
        string string_value;
        int int_value;
        char char_value;
    };
};

...

 I do see an issue here with the Standard wording. It appears the intent was to allow code like this, but I think by a strict reading, the ~StringIntChar destructor is ill-formed.

The anonymous union type has a destructor which is implicitly declared as deleted. For any other special member function, this deleted member isn't necessarily a problem for the containing class StringIntChar, since a user-defined special member just won't call the member of the anonymous union. But for destructors, [class.dtor]/14 says

After executing the body of the destructor and destroying any objects with automatic storage duration allocated within the body, a destructor for class X calls the destructors for X's direct non-variant non-static data members, the destructors for X's non-virtual direct base classes and, if X is the most derived class ([class.base.init]), its destructor calls the destructors for X's virtual base classes.

I think the "non-variant" phrasing reflects an intent to make code like the example valid. But the subobject whose type is the anonymous union is still a "direct non-variant non-static data member" of StringIntChar, so any StringIntChar destructor still involves a call to the union's deleted destructor, and so is ill-formed.

Worth a Defect Report, does anyone think?

-- Andrew Schepler