An ill-formed C++ code snippet
Before the fix, this following C++ snippet would crash Clang. From the bug report, we can see how a user might accidentally omit the function name when they meant to declare a member function on line 3.
To many people’s surprise, line 3 is actually parsed as a member variable declaration.
The parantheses are insignificant here unlike when declaring a pointer to function or array. So line 3 is essentially T A<T>{};
.
The template parameter there is ill-formed and is handled by 942c03910aef.
Why crash?
The core of this problem is that the identifier part of the ill-formed member variable declaration is empty inside Clang’s AST,
when handling the default member initializer (the {}
on line 3 of crash.cpp
) inside clang::Sema::BuildCXXDefaultInitExpr
.
Here’s an excerpt from clang::Sema::BuildCXXDefaultInitExpr
.
The range-based for loop is never run as the Lookup
is empty!
Pattern
stays as nullptr
.
This triggers an asssertion failure at
clang/lib/Sema/SemaDeclCXX.cpp:15540 if NDEBUG
is not defined.
Otherwise, Pattern
is accessed 😱 at
clang/lib/Sema/SemaDeclCXX.cpp:15542,
the bahavior of which is undefined 💣 💥.
clang::Sema::BuildCXXDefaultInitExpr
is call stack #12 in the crash backtrace below:
The fix
Simply adding a line to set the identifier of an ill-formed declarator would suffice.
Now the name clash with the injected-class-name can also be correctly diagnosed as shown below 🎊 🙌 🎉: