The following valid(afaik) program is rejected by gcc. https://godbolt.org/z/e73Yf4s47 ``` #include <variant> struct LiteralExpr { int value; }; template <typename T> struct BaseSpace { struct AddExpr; struct AddExprBox { const AddExpr &_impl; public: AddExprBox(const AddExpr &obj) {} }; using Expr = std::variant<AddExprBox, LiteralExpr>; struct AddExpr { std::variant<AddExprBox, LiteralExpr> lhs; // error: 'BaseSpace<T>::AddExpr::lhs' has incomplete type }; }; auto main() -> int { auto expr = BaseSpace<int>::Expr(LiteralExpr{2}); } ``` The error says: ``` error: 'BaseSpace<T>::AddExpr::lhs' has incomplete type 22 | std::variant<AddExprBox, LiteralExpr> lhs; | ^~~ In file included from <source>:1: /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/variant:1336:11: note: declaration of 'class std::variant<BaseSpace<int>::AddExprBox, LiteralExpr>' 1336 | class variant | ^~~~~~~ ```
clang rejects it with the same error message. Both GCC and clang are correct because the inner types are not complete until after the outer type is complete.
(In reply to Andrew Pinski from comment #1) > clang rejects it with the same error message. > > Both GCC and clang are correct because the inner types are not complete > until after the outer type is complete. I don't think what you said about " inner types are not complete until after the outer type is complete" is true. In particular, the following program is well-formed. Note in the below program the nested type named `A` is complete when its `};` is encountered and not when the containing class `C`'s `};` is encountered as opposed to your claim. ``` struct C { struct A { }; static constexpr A a{}; //this is fine because A is complete here as opposed to Andrew's claim }; ```
Dup of bug 96645. *** This bug has been marked as a duplicate of bug 96645 ***
Also see PR 102199. Also see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165#c10 (which references when the inner class type is complete). This is one of the dark corners of C++ which have issues with many things.