pjessesco created this revision. pjessesco requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
https://github.com/llvm/llvm-project/issues/44601 This patch handles a bug when parsing a below example code : template <class> class S; template <class T> bool operator<(S<T> const &x, S<T> const &y) { return x.i < y.i; } template <class T> class S { int i = 42; friend bool operator<<>(S const &, S const &); }; int main() { return S<int>{} < S<int>{}; } which parse `<<>` to `<< >`, not `< <>` in terms of tokens as discussed in discord. 1. Add a condition in `tryMergeLessLess()` considering `operator` keyword and `>` 2. Force to leave a whitespace between `tok::less` and a template opener 3. Add unit test Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D117398 Files: clang/lib/Format/FormatTokenLexer.cpp clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTest.cpp Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -9275,6 +9275,7 @@ verifyFormat("operator SomeType<int>();"); verifyFormat("operator SomeType<int, int>();"); verifyFormat("operator SomeType<SomeType<int>>();"); + verifyFormat("operator< <>();"); verifyFormat("void *operator new(std::size_t size);"); verifyFormat("void *operator new[](std::size_t size);"); verifyFormat("void operator delete(void *ptr);"); Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -3345,6 +3345,8 @@ if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) && !Left.opensScope() && Style.SpaceBeforeCpp11BracedList) return true; + if (Left.is(tok::less) && Right.is(TT_TemplateOpener)) + return true; } else if (Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) { if (Right.is(tok::period) && Index: clang/lib/Format/FormatTokenLexer.cpp =================================================================== --- clang/lib/Format/FormatTokenLexer.cpp +++ clang/lib/Format/FormatTokenLexer.cpp @@ -429,9 +429,10 @@ if (Tokens.size() < 3) return false; + auto Forth = (Tokens.end() - 4)[0]; bool FourthTokenIsLess = false; if (Tokens.size() > 3) - FourthTokenIsLess = (Tokens.end() - 4)[0]->is(tok::less); + FourthTokenIsLess = Forth->is(tok::less); auto First = Tokens.end() - 3; if (First[2]->is(tok::less) || First[1]->isNot(tok::less) || @@ -443,6 +444,10 @@ First[1]->WhitespaceRange.getEnd()) return false; + // Do not remove a whitespace between the two "<" e.g. "operator<<>". + if (First[2]->is(tok::greater) && Forth->is(tok::kw_operator)) + return false; + First[0]->Tok.setKind(tok::lessless); First[0]->TokenText = "<<"; First[0]->ColumnWidth += 1;
Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -9275,6 +9275,7 @@ verifyFormat("operator SomeType<int>();"); verifyFormat("operator SomeType<int, int>();"); verifyFormat("operator SomeType<SomeType<int>>();"); + verifyFormat("operator< <>();"); verifyFormat("void *operator new(std::size_t size);"); verifyFormat("void *operator new[](std::size_t size);"); verifyFormat("void operator delete(void *ptr);"); Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -3345,6 +3345,8 @@ if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) && !Left.opensScope() && Style.SpaceBeforeCpp11BracedList) return true; + if (Left.is(tok::less) && Right.is(TT_TemplateOpener)) + return true; } else if (Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) { if (Right.is(tok::period) && Index: clang/lib/Format/FormatTokenLexer.cpp =================================================================== --- clang/lib/Format/FormatTokenLexer.cpp +++ clang/lib/Format/FormatTokenLexer.cpp @@ -429,9 +429,10 @@ if (Tokens.size() < 3) return false; + auto Forth = (Tokens.end() - 4)[0]; bool FourthTokenIsLess = false; if (Tokens.size() > 3) - FourthTokenIsLess = (Tokens.end() - 4)[0]->is(tok::less); + FourthTokenIsLess = Forth->is(tok::less); auto First = Tokens.end() - 3; if (First[2]->is(tok::less) || First[1]->isNot(tok::less) || @@ -443,6 +444,10 @@ First[1]->WhitespaceRange.getEnd()) return false; + // Do not remove a whitespace between the two "<" e.g. "operator<<>". + if (First[2]->is(tok::greater) && Forth->is(tok::kw_operator)) + return false; + First[0]->Tok.setKind(tok::lessless); First[0]->TokenText = "<<"; First[0]->ColumnWidth += 1;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits