Skip to content

Commit 89cd0e8

Browse files
committed
[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.
1 parent 0301a49 commit 89cd0e8

File tree

9 files changed

+60
-6
lines changed

9 files changed

+60
-6
lines changed

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,16 @@ ClangExpressionParser::ClangExpressionParser(
509509
// be re-evaluated in the future.
510510
lang_opts.CPlusPlus11 = true;
511511
break;
512+
case lldb::eLanguageTypeC_plus_plus_20:
513+
lang_opts.CPlusPlus20 = true;
514+
LLVM_FALLTHROUGH;
515+
case lldb::eLanguageTypeC_plus_plus_17:
516+
// FIXME: add a separate case for CPlusPlus14. Currently folded into C++17
517+
// because C++14 is the default standard for Clang but enabling CPlusPlus14
518+
// expression evaluatino doesn't pass the test-suite cleanly.
519+
lang_opts.CPlusPlus14 = true;
520+
lang_opts.CPlusPlus17 = true;
521+
LLVM_FALLTHROUGH;
512522
case lldb::eLanguageTypeC_plus_plus:
513523
case lldb::eLanguageTypeC_plus_plus_11:
514524
case lldb::eLanguageTypeC_plus_plus_14:

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ TokenVerifier::TokenVerifier(std::string body) {
274274
LangOptions Opts;
275275
Opts.ObjC = true;
276276
Opts.DollarIdents = true;
277-
Opts.CPlusPlus17 = true;
277+
Opts.CPlusPlus20 = true;
278278
Opts.LineComment = true;
279279

280280
Lexer lex(FID, buf->getMemBufferRef(), SM, Opts);

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,7 @@ static const clang::LangOptions &GetLangOptions() {
750750
g_options.CPlusPlus11 = true;
751751
g_options.CPlusPlus14 = true;
752752
g_options.CPlusPlus17 = true;
753+
g_options.CPlusPlus20 = true;
753754
});
754755
return g_options;
755756
}

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ bool TypeSystemClang::IsOperator(llvm::StringRef name,
399399
.Case("=", clang::OO_Equal)
400400
.Case("==", clang::OO_EqualEqual)
401401
.Case("<", clang::OO_Less)
402+
.Case("<=>", clang::OO_Spaceship)
402403
.Case("<<", clang::OO_LessLess)
403404
.Case("<<=", clang::OO_LessLessEqual)
404405
.Case("<=", clang::OO_LessEqual)
@@ -510,6 +511,9 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) {
510511
Opts.C99 = Std.isC99();
511512
Opts.CPlusPlus = Std.isCPlusPlus();
512513
Opts.CPlusPlus11 = Std.isCPlusPlus11();
514+
Opts.CPlusPlus14 = Std.isCPlusPlus14();
515+
Opts.CPlusPlus17 = Std.isCPlusPlus17();
516+
Opts.CPlusPlus20 = Std.isCPlusPlus20();
513517
Opts.Digraphs = Std.hasDigraphs();
514518
Opts.GNUMode = Std.isGNUMode();
515519
Opts.GNUInline = !Std.isC99();
@@ -627,6 +631,8 @@ LanguageSet TypeSystemClang::GetSupportedLanguagesForTypes() {
627631
languages.Insert(lldb::eLanguageTypeC_plus_plus_11);
628632
languages.Insert(lldb::eLanguageTypeC11);
629633
languages.Insert(lldb::eLanguageTypeC_plus_plus_14);
634+
languages.Insert(lldb::eLanguageTypeC_plus_plus_17);
635+
languages.Insert(lldb::eLanguageTypeC_plus_plus_20);
630636
return languages;
631637
}
632638

@@ -637,6 +643,8 @@ LanguageSet TypeSystemClang::GetSupportedLanguagesForExpressions() {
637643
languages.Insert(lldb::eLanguageTypeC_plus_plus_03);
638644
languages.Insert(lldb::eLanguageTypeC_plus_plus_11);
639645
languages.Insert(lldb::eLanguageTypeC_plus_plus_14);
646+
languages.Insert(lldb::eLanguageTypeC_plus_plus_17);
647+
languages.Insert(lldb::eLanguageTypeC_plus_plus_20);
640648
return languages;
641649
}
642650

lldb/source/Target/Language.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ bool Language::LanguageIsCPlusPlus(LanguageType language) {
267267
case eLanguageTypeC_plus_plus_03:
268268
case eLanguageTypeC_plus_plus_11:
269269
case eLanguageTypeC_plus_plus_14:
270+
case eLanguageTypeC_plus_plus_17:
271+
case eLanguageTypeC_plus_plus_20:
270272
case eLanguageTypeObjC_plus_plus:
271273
return true;
272274
default:
@@ -306,6 +308,8 @@ bool Language::LanguageIsCFamily(LanguageType language) {
306308
case eLanguageTypeC_plus_plus_03:
307309
case eLanguageTypeC_plus_plus_11:
308310
case eLanguageTypeC_plus_plus_14:
311+
case eLanguageTypeC_plus_plus_17:
312+
case eLanguageTypeC_plus_plus_20:
309313
case eLanguageTypeObjC_plus_plus:
310314
case eLanguageTypeObjC:
311315
return true;
@@ -329,6 +333,8 @@ LanguageType Language::GetPrimaryLanguage(LanguageType language) {
329333
case eLanguageTypeC_plus_plus_03:
330334
case eLanguageTypeC_plus_plus_11:
331335
case eLanguageTypeC_plus_plus_14:
336+
case eLanguageTypeC_plus_plus_17:
337+
case eLanguageTypeC_plus_plus_20:
332338
return eLanguageTypeC_plus_plus;
333339
case eLanguageTypeC:
334340
case eLanguageTypeC89:
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CXX_SOURCES := main.cpp
2+
CXXFLAGS_EXTRAS := -std=c++20
3+
4+
include Makefile.rules
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test import lldbutil
5+
6+
class TestCPP20Standard(TestBase):
7+
def test_cpp20(self):
8+
"""
9+
Tests that we can evaluate an expression in C++20 mode
10+
"""
11+
self.build()
12+
lldbutil.run_to_source_breakpoint(self, "Foo{}", lldb.SBFileSpec("main.cpp"))
13+
14+
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"])
15+
16+
self.expect("expr -l c++20 -- Foo{} <=> Foo{}", substrs=["(bool) $0 = true"])
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <compare>
2+
3+
struct Foo {
4+
friend auto operator<=>(Foo const &, Foo const &) { return true; }
5+
};
6+
7+
int main() { return Foo{} <=> Foo{}; }

lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,11 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
205205

206206
{"auto Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>(int) &", "auto",
207207
"Foo[abi:abc]<int>", "operator<<<Foo[abi:abc]<int>>", "(int)", "&",
208-
"Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>"}};
208+
"Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>"},
209+
210+
{"auto A::operator<=>[abi:tag]<A::B>()", "auto", "A",
211+
"operator<=>[abi:tag]<A::B>", "()", "",
212+
"A::operator<=>[abi:tag]<A::B>"}};
209213

210214
for (const auto &test : test_cases) {
211215
CPlusPlusLanguage::MethodName method(ConstString(test.input));
@@ -227,7 +231,6 @@ TEST(CPlusPlusLanguage, InvalidMethodNameParsing) {
227231
std::string test_cases[] = {
228232
"int Foo::operator[]<[10>()",
229233
"Foo::operator bool[10]()",
230-
"auto A::operator<=>[abi:tag]<A::B>()",
231234
"auto A::operator<<<(int)",
232235
"auto A::operator>>>(int)",
233236
"auto A::operator<<<Type[abi:tag]<>(int)",
@@ -356,10 +359,9 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) {
356359
EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
357360
"f<A<B><C>>", context, basename));
358361

359-
// We expect these cases to fail until we turn on C++2a
360-
EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
362+
EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier(
361363
"A::operator<=><A::B>", context, basename));
362-
EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
364+
EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier(
363365
"operator<=><A::B>", context, basename));
364366
}
365367

0 commit comments

Comments
 (0)