Author: Michael Buch Date: 2023-04-14T17:10:18+01:00 New Revision: 89cd0e8c267f57004a734c94ff15c6bd0facf646
URL: https://github.com/llvm/llvm-project/commit/89cd0e8c267f57004a734c94ff15c6bd0facf646 DIFF: https://github.com/llvm/llvm-project/commit/89cd0e8c267f57004a734c94ff15c6bd0facf646.diff LOG: [lldb] Allow evaluating expressions in C++20 mode This patch allows users to evaluate expressions using `expr -l c++20`. Currently DWARF keeps the CU's at `DW_AT_language` at `DW_LANG_C_plus_plus_14` even when compiling with `-std=c++20`. So even in "C++20 programs" expression evaluation will by default be performed in `C++11` mode for now. Enabling `C++14` has been previously attempted at https://reviews.llvm.org/D80308 There are some remaining issues around evaluating C++20 expressions. Mainly, lack of support for C++20 AST nodes in `clang::ASTImporter`. But these can be addressed in follow-up patches. Added: lldb/test/API/lang/cpp/standards/cpp20/Makefile lldb/test/API/lang/cpp/standards/cpp20/TestCPP20Standard.py lldb/test/API/lang/cpp/standards/cpp20/main.cpp Modified: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp lldb/source/Target/Language.cpp lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 9852bbc62aa4..79666ffadb08 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -509,6 +509,16 @@ ClangExpressionParser::ClangExpressionParser( // be re-evaluated in the future. lang_opts.CPlusPlus11 = true; break; + case lldb::eLanguageTypeC_plus_plus_20: + lang_opts.CPlusPlus20 = true; + LLVM_FALLTHROUGH; + case lldb::eLanguageTypeC_plus_plus_17: + // FIXME: add a separate case for CPlusPlus14. Currently folded into C++17 + // because C++14 is the default standard for Clang but enabling CPlusPlus14 + // expression evaluatino doesn't pass the test-suite cleanly. + lang_opts.CPlusPlus14 = true; + lang_opts.CPlusPlus17 = true; + LLVM_FALLTHROUGH; case lldb::eLanguageTypeC_plus_plus: case lldb::eLanguageTypeC_plus_plus_11: case lldb::eLanguageTypeC_plus_plus_14: diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index 527055024a76..68e25618f78b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -274,7 +274,7 @@ TokenVerifier::TokenVerifier(std::string body) { LangOptions Opts; Opts.ObjC = true; Opts.DollarIdents = true; - Opts.CPlusPlus17 = true; + Opts.CPlusPlus20 = true; Opts.LineComment = true; Lexer lex(FID, buf->getMemBufferRef(), SM, Opts); diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index 1f7d8a1b8598..d8c095d6edeb 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -750,6 +750,7 @@ static const clang::LangOptions &GetLangOptions() { g_options.CPlusPlus11 = true; g_options.CPlusPlus14 = true; g_options.CPlusPlus17 = true; + g_options.CPlusPlus20 = true; }); return g_options; } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index b661ec445332..15747136d59c 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -399,6 +399,7 @@ bool TypeSystemClang::IsOperator(llvm::StringRef name, .Case("=", clang::OO_Equal) .Case("==", clang::OO_EqualEqual) .Case("<", clang::OO_Less) + .Case("<=>", clang::OO_Spaceship) .Case("<<", clang::OO_LessLess) .Case("<<=", clang::OO_LessLessEqual) .Case("<=", clang::OO_LessEqual) @@ -510,6 +511,9 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { Opts.C99 = Std.isC99(); Opts.CPlusPlus = Std.isCPlusPlus(); Opts.CPlusPlus11 = Std.isCPlusPlus11(); + Opts.CPlusPlus14 = Std.isCPlusPlus14(); + Opts.CPlusPlus17 = Std.isCPlusPlus17(); + Opts.CPlusPlus20 = Std.isCPlusPlus20(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); Opts.GNUInline = !Std.isC99(); @@ -627,6 +631,8 @@ LanguageSet TypeSystemClang::GetSupportedLanguagesForTypes() { languages.Insert(lldb::eLanguageTypeC_plus_plus_11); languages.Insert(lldb::eLanguageTypeC11); languages.Insert(lldb::eLanguageTypeC_plus_plus_14); + languages.Insert(lldb::eLanguageTypeC_plus_plus_17); + languages.Insert(lldb::eLanguageTypeC_plus_plus_20); return languages; } @@ -637,6 +643,8 @@ LanguageSet TypeSystemClang::GetSupportedLanguagesForExpressions() { languages.Insert(lldb::eLanguageTypeC_plus_plus_03); languages.Insert(lldb::eLanguageTypeC_plus_plus_11); languages.Insert(lldb::eLanguageTypeC_plus_plus_14); + languages.Insert(lldb::eLanguageTypeC_plus_plus_17); + languages.Insert(lldb::eLanguageTypeC_plus_plus_20); return languages; } diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp index 9f3899003f0d..c490378e96de 100644 --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -267,6 +267,8 @@ bool Language::LanguageIsCPlusPlus(LanguageType language) { case eLanguageTypeC_plus_plus_03: case eLanguageTypeC_plus_plus_11: case eLanguageTypeC_plus_plus_14: + case eLanguageTypeC_plus_plus_17: + case eLanguageTypeC_plus_plus_20: case eLanguageTypeObjC_plus_plus: return true; default: @@ -306,6 +308,8 @@ bool Language::LanguageIsCFamily(LanguageType language) { case eLanguageTypeC_plus_plus_03: case eLanguageTypeC_plus_plus_11: case eLanguageTypeC_plus_plus_14: + case eLanguageTypeC_plus_plus_17: + case eLanguageTypeC_plus_plus_20: case eLanguageTypeObjC_plus_plus: case eLanguageTypeObjC: return true; @@ -329,6 +333,8 @@ LanguageType Language::GetPrimaryLanguage(LanguageType language) { case eLanguageTypeC_plus_plus_03: case eLanguageTypeC_plus_plus_11: case eLanguageTypeC_plus_plus_14: + case eLanguageTypeC_plus_plus_17: + case eLanguageTypeC_plus_plus_20: return eLanguageTypeC_plus_plus; case eLanguageTypeC: case eLanguageTypeC89: diff --git a/lldb/test/API/lang/cpp/standards/cpp20/Makefile b/lldb/test/API/lang/cpp/standards/cpp20/Makefile new file mode 100644 index 000000000000..4f79c0a900c3 --- /dev/null +++ b/lldb/test/API/lang/cpp/standards/cpp20/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp +CXXFLAGS_EXTRAS := -std=c++20 + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/standards/cpp20/TestCPP20Standard.py b/lldb/test/API/lang/cpp/standards/cpp20/TestCPP20Standard.py new file mode 100644 index 000000000000..dbca9092e3ab --- /dev/null +++ b/lldb/test/API/lang/cpp/standards/cpp20/TestCPP20Standard.py @@ -0,0 +1,16 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestCPP20Standard(TestBase): + def test_cpp20(self): + """ + Tests that we can evaluate an expression in C++20 mode + """ + self.build() + lldbutil.run_to_source_breakpoint(self, "Foo{}", lldb.SBFileSpec("main.cpp")) + + self.expect("expr -l c++11 -- Foo{} <=> Foo{}", error=True, substrs=["'<=>' is a single token in C++20; add a space to avoid a change in behavior"]) + + self.expect("expr -l c++20 -- Foo{} <=> Foo{}", substrs=["(bool) $0 = true"]) diff --git a/lldb/test/API/lang/cpp/standards/cpp20/main.cpp b/lldb/test/API/lang/cpp/standards/cpp20/main.cpp new file mode 100644 index 000000000000..e49a4fc5fff6 --- /dev/null +++ b/lldb/test/API/lang/cpp/standards/cpp20/main.cpp @@ -0,0 +1,7 @@ +#include <compare> + +struct Foo { + friend auto operator<=>(Foo const &, Foo const &) { return true; } +}; + +int main() { return Foo{} <=> Foo{}; } diff --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp index 6c85ed159df5..cfdc3163f6a3 100644 --- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp +++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp @@ -205,7 +205,11 @@ TEST(CPlusPlusLanguage, MethodNameParsing) { {"auto Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>(int) &", "auto", "Foo[abi:abc]<int>", "operator<<<Foo[abi:abc]<int>>", "(int)", "&", - "Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>"}}; + "Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>"}, + + {"auto A::operator<=>[abi:tag]<A::B>()", "auto", "A", + "operator<=>[abi:tag]<A::B>", "()", "", + "A::operator<=>[abi:tag]<A::B>"}}; for (const auto &test : test_cases) { CPlusPlusLanguage::MethodName method(ConstString(test.input)); @@ -227,7 +231,6 @@ TEST(CPlusPlusLanguage, InvalidMethodNameParsing) { std::string test_cases[] = { "int Foo::operator[]<[10>()", "Foo::operator bool[10]()", - "auto A::operator<=>[abi:tag]<A::B>()", "auto A::operator<<<(int)", "auto A::operator>>>(int)", "auto A::operator<<<Type[abi:tag]<>(int)", @@ -356,10 +359,9 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) { EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( "f<A<B><C>>", context, basename)); - // We expect these cases to fail until we turn on C++2a - EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier( "A::operator<=><A::B>", context, basename)); - EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier( "operator<=><A::B>", context, basename)); } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits