An ill-formed C++ code snippet

Before the fix, this following C++ snippet would crash Clang. crash-cpp 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. excerpt 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: before

The fix

Simply adding a line to set the identifier of an ill-formed declarator would suffice. fix

Now the name clash with the injected-class-name can also be correctly diagnosed as shown below 🎊 🙌 🎉: after