Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,12 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {

QualType class_qual_type = m_ast_context->getCanonicalTagType(class_decl);

// The synthesized __lldb_expr will adopt the qualifiers from this class
// type. Make sure we use the qualifiers of the method that we're currently
// stopped in.
class_qual_type.addFastQualifiers(
method_decl->getMethodQualifiers().getFastQualifiers());

TypeFromUser class_user_type(
class_qual_type.getAsOpaquePtr(),
function_decl_ctx.GetTypeSystem()->weak_from_this());
Expand Down Expand Up @@ -1991,7 +1997,7 @@ void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
std::array<CompilerType, 1> args{void_clang_type.GetPointerType()};

CompilerType method_type = m_clang_ast_context->CreateFunctionType(
void_clang_type, args, false, 0);
void_clang_type, args, false, ut.GetTypeQualifiers());

const bool is_virtual = false;
const bool is_static = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "ClangExpressionUtil.h"

#include "clang/AST/TypeBase.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
Expand Down Expand Up @@ -189,6 +190,28 @@ static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit,
}
}

/// Return qualifers of the current C++ method.
static clang::Qualifiers GetFrameCVQualifiers(StackFrame *frame) {
if (!frame)
return {};

auto this_sp = frame->FindVariable(ConstString("this"));
if (!this_sp)
return {};

// Lambdas that capture 'this' have a member variable called 'this'. The class
// context of __lldb_expr for a lambda is the class type of the 'this' capture
// (not the anonymous lambda structure). So use the qualifiers of the captured
// 'this'.
if (auto this_this_sp = this_sp->GetChildMemberWithName("this"))
return clang::Qualifiers::fromCVRMask(
this_this_sp->GetCompilerType().GetPointeeType().GetTypeQualifiers());

// Not in a lambda. Return 'this' qualifiers.
return clang::Qualifiers::fromCVRMask(
this_sp->GetCompilerType().GetPointeeType().GetTypeQualifiers());
}

lldb_private::ClangExpressionSourceCode::ClangExpressionSourceCode(
llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix,
llvm::StringRef body, Wrapping wrap, WrapKind wrap_kind)
Expand Down Expand Up @@ -463,15 +486,17 @@ bool ClangExpressionSourceCode::GetText(
lldb_local_var_decls.GetData(), tagged_body.c_str());
break;
case WrapKind::CppMemberFunction:
wrap_stream.Printf("%s"
"void \n"
"$__lldb_class::%s(void *$__lldb_arg) \n"
"{ \n"
" %s; \n"
"%s"
"} \n",
module_imports.c_str(), m_name.c_str(),
lldb_local_var_decls.GetData(), tagged_body.c_str());
wrap_stream.Printf(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: I was always puzzled why we use Printf format strings here. It would seem that << operations would be more readable and we could avoid the c_str() conversions that recompute the length of the strings?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea we could definitely do that. Probably best as a separate clean-up?

"%s"
"void \n"
"$__lldb_class::%s(void *$__lldb_arg) %s \n"
"{ \n"
" %s; \n"
"%s"
"} \n",
module_imports.c_str(), m_name.c_str(),
GetFrameCVQualifiers(exe_ctx.GetFramePtr()).getAsString().c_str(),
lldb_local_var_decls.GetData(), tagged_body.c_str());
break;
case WrapKind::ObjCInstanceMethod:
wrap_stream.Printf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ def test_expr_inside_lambda(self):

# Inside non_capturing_method
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect_expr("local", result_type="int", result_value="5")
self.expect_expr("local2", result_type="int", result_value="10")
self.expect_expr("local", result_type="const int", result_value="5")
self.expect_expr("local2", result_type="const int", result_value="10")
self.expect_expr("local2 * local", result_type="int", result_value="50")

self.expectExprError(
Expand Down
10 changes: 4 additions & 6 deletions lldb/test/API/lang/cpp/const_this/TestConstThis.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ def run_class_tests(self):
# Expression not referencing context class.
self.expect_expr("1 + 1", result_type="int", result_value="2")
# Referencing context class.
# FIXME: This and the expression below should return const types.
self.expect_expr("member", result_type="int", result_value="3")
self.expect_expr("member", result_type="const int", result_value="3")
# Check the type of context class.
self.expect_expr("this", result_type="ContextClass *")
self.expect_expr("this", result_type="const ContextClass *")

def test_member_func(self):
self.build()
Expand All @@ -36,10 +35,9 @@ def run_template_class_tests(self):
# Expression not referencing context class.
self.expect_expr("1 + 1", result_type="int", result_value="2")
# Referencing context class.
# FIXME: This and the expression below should return const types.
self.expect_expr("member", result_type="int", result_value="4")
self.expect_expr("member", result_type="const int", result_value="4")
# Check the type of context class.
self.expect_expr("this", result_type="TemplatedContextClass<int> *")
self.expect_expr("this", result_type="const TemplatedContextClass<int> *")

def test_template_member_func(self):
self.build()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestCase(TestBase):
def test(self):
self.build()
(_, process, _, _) = lldbutil.run_to_source_breakpoint(
self, "Break: const_method begin", lldb.SBFileSpec("main.cpp")
)

self.expect_expr("bar()", result_value="2", result_type="int")
self.expect(
"expression m_const_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member",
"with const-qualified type",
],
)
self.expect(
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
],
)
self.expect_expr("((Foo*)this)->bar()", result_type="double", result_value="5")

lldbutil.continue_to_source_breakpoint(
self,
process,
"Break: const_method no-this lambda",
lldb.SBFileSpec("main.cpp"),
)

self.expect(
"expression x = 7.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
],
)

lldbutil.continue_to_source_breakpoint(
self,
process,
"Break: const_method mutable no-this lambda",
lldb.SBFileSpec("main.cpp"),
)

self.expect_expr("x = 7.0; x", result_value="7")

lldbutil.continue_to_source_breakpoint(
self, process, "Break: const_method lambda", lldb.SBFileSpec("main.cpp")
)

# FIXME: mutating this capture should be disallowed in a non-mutable lambda.
self.expect_expr("y = 8.0")
self.expect_expr("bar()", result_value="2", result_type="int")
self.expect(
"expression m_const_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member",
"with const-qualified type",
],
)
self.expect(
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
],
)
self.expect_expr("m_mem", result_value="-2")
self.expect_expr("((Foo*)this)->bar()", result_type="double", result_value="5")

lldbutil.continue_to_source_breakpoint(
self,
process,
"Break: const_method mutable lambda",
lldb.SBFileSpec("main.cpp"),
)

self.expect_expr("y = 9.0")
self.expect_expr("bar()", result_value="2", result_type="int")
self.expect(
"expression m_const_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member",
"with const-qualified type",
],
)
self.expect(
"expression m_mem = 2.0",
error=True,
substrs=[
"cannot assign to non-static data member within const member function"
],
)
self.expect_expr("m_mem", result_value="-2")
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <cassert>
#include <cstdio>

struct Foo {
double bar() { return 5.0; }

int bar() const { return 2; }

int const_method() const {
auto x = bar();
assert(x == 2);
std::puts("Break: const_method begin");

[x] {
std::puts("Keep on multiple lines...");
std::puts("Break: const_method no-this lambda");
}();

[x]() mutable {
std::puts("Keep on multiple lines...");
std::puts("Break: const_method mutable no-this lambda");
}();

[this, y = x] {
auto x = bar() + y;
std::puts("Break: const_method lambda");
}();

[this, y = x]() mutable {
auto x = bar() + y;
std::puts("Break: const_method mutable lambda");
}();

return 120;
}

float m_mem = -2.0;
const float m_const_mem = -3.0;
};

int main() {
const Foo f;
f.bar();

Foo f2;
f2.bar();

return Foo{}.const_method();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestCase(TestBase):
def test(self):
self.build()
(_, process, _, _) = lldbutil.run_to_source_breakpoint(
self, "Break here: const", lldb.SBFileSpec("main.cpp")
)

self.expect_expr("bar()", result_type="double", result_value="5")
self.expect_expr("const_volatile_method()")
self.expect_expr("const_method()")
self.expect(
"expression volatile_method()",
error=True,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can this not be expect_expr?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expect_expr asserts that the expression succeeded. So if we want to expect that an expression failed, we have to resort to expect

substrs=["has type 'const Foo'", "but function is not marked const"],
)

lldbutil.continue_to_source_breakpoint(
self, process, "Break here: volatile", lldb.SBFileSpec("main.cpp")
)

self.expect_expr(
"bar()", result_type="const char *", result_summary='"volatile_bar"'
)
self.expect_expr("const_volatile_method()")
self.expect(
"expression const_method()",
error=True,
substrs=["has type 'volatile Foo'", "but function is not marked volatile"],
)
self.expect_expr("volatile_method()")

lldbutil.continue_to_source_breakpoint(
self, process, "Break here: const volatile", lldb.SBFileSpec("main.cpp")
)

self.expect_expr("bar()", result_type="int", result_value="2")
self.expect_expr("other_cv_method()")

self.expect(
"expression const_method()",
error=True,
substrs=[
"has type 'const volatile Foo'",
"but function is not marked const or volatile",
],
)
self.expect(
"expression volatile_method()",
error=True,
substrs=[
"has type 'const volatile Foo'",
"but function is not marked const or volatile",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <cassert>
#include <cstdio>

struct Foo {
double bar() const { return 5.0; }
const char *bar() volatile { return "volatile_bar"; }
int bar() volatile const { return 2; }

int volatile_method() volatile {
std::puts("Break here: volatile");
return 0;
}
int const_method() const {
std::puts("Break here: const");
return 0;
}
int other_cv_method() const volatile { return 20; }

int const_volatile_method() const volatile {
auto x = bar();
assert(x == 2);
other_cv_method();

std::puts("Break here: const volatile");

return 120;
}
};

int main() {
const Foo f;
f.bar();
f.const_method();

volatile Foo f2;
f2.bar();
f2.volatile_method();

const volatile Foo f3;
f3.bar();

return Foo{}.const_volatile_method();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Loading
Loading