[Lldb-commits] [lldb] 89cd0e8 - [lldb] Allow evaluating expressions in C++20 mode

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 14 09:10:48 PDT 2023


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));
 }
 


        


More information about the lldb-commits mailing list