From: shafik Date: Fri, 27 Mar 2020 21:12:38 +0000 (-0700) Subject: [LLDB] CPlusPlusNameParser does not handles templated operator< properly X-Git-Tag: llvmorg-12-init~10894 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8016d61e3cf4967dd28c8f6296cec685dadcaee6;p=platform%2Fupstream%2Fllvm.git [LLDB] CPlusPlusNameParser does not handles templated operator< properly CPlusPlusNameParser is used in several places on of them is during IR execution and setting breakpoints to pull information C++ like the basename, the context and arguments. Currently it does not handle templated operator< properly, because of idiosyncrasy is how clang generates debug info for these cases. It uses clang::Lexer which will tokenize operator< into: tok::kw_operator tok::lessless tok::raw_identifier Later on the parser in ConsumeOperator() does not handle this case properly and we end up failing to parse. Differential Revision: https://reviews.llvm.org/D76168 --- diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index fb85609..a834be9 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -329,6 +329,37 @@ bool CPlusPlusNameParser::ConsumeOperator() { } const auto &token = Peek(); + + // When clang generates debug info it adds template parameters to names. + // Since clang doesn't add a space between the name and the template parameter + // in some cases we are not generating valid C++ names e.g.: + // + // operator< + // + // In some of these cases we will not parse them correctly. This fixes the + // issue by detecting this case and inserting tok::less in place of + // tok::lessless and returning successfully that we consumed the operator. + if (token.getKind() == tok::lessless) { + // Make sure we have more tokens before attempting to look ahead one more. + if (m_next_token_index + 1 < m_tokens.size()) { + // Look ahead two tokens. + clang::Token n_token = m_tokens[m_next_token_index + 1]; + // If we find ( or < then this is indeed operator<< no need for fix. + if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) { + clang::Token tmp_tok; + + tmp_tok.setLength(1); + tmp_tok.setLocation(token.getLocation().getLocWithOffset(1)); + tmp_tok.setKind(tok::less); + + m_tokens[m_next_token_index] = tmp_tok; + + start_position.Remove(); + return true; + } + } + } + switch (token.getKind()) { case tok::kw_new: case tok::kw_delete: diff --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp index 4928534..e8e6a4c 100644 --- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp +++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp @@ -140,12 +140,20 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) { "std::vector>", "_M_emplace_back_aux"}, {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"}, - {"`operator<'::`2'::B<0>::operator>", - "`operator<'::`2'::B<0>", + {"`operator<'::`2'::B<0>::operator>", "`operator<'::`2'::B<0>", "operator>"}, {"`anonymous namespace'::S::<<::__l2::Foo", - "`anonymous namespace'::S::<<::__l2", - "Foo"}}; + "`anonymous namespace'::S::<<::__l2", "Foo"}, + // These cases are idiosyncratic in how clang generates debug info for + // names when we have template parameters. They are not valid C++ names + // but if we fix this we need to support them for older compilers. + {"A::operator>", "A", "operator>"}, + {"operator>", "", "operator>"}, + {"A::operator<", "A", "operator<"}, + {"operator<", "", "operator<"}, + {"A::operator<<", "A", "operator<<"}, + {"operator<<", "", "operator<<"}, + }; llvm::StringRef context, basename; for (const auto &test : test_cases) { @@ -169,6 +177,12 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) { "abc::", context, basename)); EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( "f>", context, basename)); + + // We expect these cases to fail until we turn on C++2a + EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + "A::operator<=>", context, basename)); + EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + "operator<=>", context, basename)); } static std::set FindAlternate(llvm::StringRef Name) {