diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -509,6 +509,16 @@ // 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 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -274,7 +274,7 @@ 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 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -750,6 +750,7 @@ 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 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -399,6 +399,7 @@ .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 @@ 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 @@ 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 @@ 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 --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -267,6 +267,8 @@ 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 @@ 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 @@ 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 --- /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 --- /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 --- /dev/null +++ b/lldb/test/API/lang/cpp/standards/cpp20/main.cpp @@ -0,0 +1,7 @@ +#include + +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 --- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp +++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp @@ -205,7 +205,11 @@ {"auto Foo[abi:abc]::operator<<>(int) &", "auto", "Foo[abi:abc]", "operator<<>", "(int)", "&", - "Foo[abi:abc]::operator<<>"}}; + "Foo[abi:abc]::operator<<>"}, + + {"auto A::operator<=>[abi:tag]()", "auto", "A", + "operator<=>[abi:tag]", "()", "", + "A::operator<=>[abi:tag]"}}; for (const auto &test : test_cases) { CPlusPlusLanguage::MethodName method(ConstString(test.input)); @@ -227,7 +231,6 @@ std::string test_cases[] = { "int Foo::operator[]<[10>()", "Foo::operator bool[10]()", - "auto A::operator<=>[abi:tag]()", "auto A::operator<<<(int)", "auto A::operator>>>(int)", "auto A::operator<<(int)", @@ -356,10 +359,9 @@ EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( "f>", context, basename)); - // We expect these cases to fail until we turn on C++2a - EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier( "A::operator<=>", context, basename)); - EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier( "operator<=>", context, basename)); }