Skip to content

Commit

Permalink
[lldb] Allow evaluating expressions in C++20 mode
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Michael137 committed Apr 14, 2023
1 parent 0301a49 commit 89cd0e8
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 6 deletions.
Expand Up @@ -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:
Expand Down
Expand Up @@ -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);
Expand Down
Expand Up @@ -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;
}
Expand Down
8 changes: 8 additions & 0 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Target/Language.cpp
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions lldb/test/API/lang/cpp/standards/cpp20/Makefile
@@ -0,0 +1,4 @@
CXX_SOURCES := main.cpp
CXXFLAGS_EXTRAS := -std=c++20

include Makefile.rules
16 changes: 16 additions & 0 deletions 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"])
7 changes: 7 additions & 0 deletions 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{}; }
12 changes: 7 additions & 5 deletions lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
Expand Up @@ -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));
Expand All @@ -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)",
Expand Down Expand Up @@ -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));
}

Expand Down

0 comments on commit 89cd0e8

Please sign in to comment.