diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -10,6 +10,7 @@ #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H #include "clang/AST/CharUnits.h" +#include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -303,6 +304,10 @@ uint32_t bit_stride = 0; uint32_t byte_stride = 0; uint32_t encoding = 0; + clang::RefQualifierKind ref_qual = + clang::RQ_None; ///< Indicates ref-qualifier of + ///< C++ member function if present. + ///< Is RQ_None otherwise. }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -36,12 +36,12 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" -#include "llvm/Demangle/Demangle.h" - #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Type.h" +#include "llvm/Demangle/Demangle.h" #include #include @@ -412,6 +412,12 @@ case DW_AT_export_symbols: exports_symbols = form_value.Boolean(); break; + case DW_AT_rvalue_reference: + ref_qual = clang::RQ_RValue; + break; + case DW_AT_reference: + ref_qual = clang::RQ_LValue; + break; } } } @@ -974,9 +980,10 @@ // clang_type will get the function prototype clang type after this // call - CompilerType clang_type = m_ast.CreateFunctionType( - return_clang_type, function_param_types.data(), - function_param_types.size(), is_variadic, type_quals, calling_convention); + CompilerType clang_type = + m_ast.CreateFunctionType(return_clang_type, function_param_types.data(), + function_param_types.size(), is_variadic, + type_quals, calling_convention, attrs.ref_qual); if (attrs.name) { bool type_handled = false; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -23,6 +23,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTFwd.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/SmallVector.h" @@ -398,10 +399,11 @@ llvm::StringRef name, const CompilerType &function_Type, clang::StorageClass storage, bool is_inline); - CompilerType CreateFunctionType(const CompilerType &result_type, - const CompilerType *args, unsigned num_args, - bool is_variadic, unsigned type_quals, - clang::CallingConv cc = clang::CC_C); + CompilerType + CreateFunctionType(const CompilerType &result_type, const CompilerType *args, + unsigned num_args, bool is_variadic, unsigned type_quals, + clang::CallingConv cc = clang::CC_C, + clang::RefQualifierKind ref_qual = clang::RQ_None); clang::ParmVarDecl * CreateParameterDeclaration(clang::DeclContext *decl_ctx, 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 @@ -2168,11 +2168,10 @@ return func_decl; } -CompilerType -TypeSystemClang::CreateFunctionType(const CompilerType &result_type, - const CompilerType *args, unsigned num_args, - bool is_variadic, unsigned type_quals, - clang::CallingConv cc) { +CompilerType TypeSystemClang::CreateFunctionType( + const CompilerType &result_type, const CompilerType *args, + unsigned num_args, bool is_variadic, unsigned type_quals, + clang::CallingConv cc, clang::RefQualifierKind ref_qual) { if (!result_type || !ClangUtil::IsClangType(result_type)) return CompilerType(); // invalid return type @@ -2201,7 +2200,7 @@ proto_info.Variadic = is_variadic; proto_info.ExceptionSpec = EST_None; proto_info.TypeQuals = clang::Qualifiers::fromFastMask(type_quals); - proto_info.RefQualifier = RQ_None; + proto_info.RefQualifier = ref_qual; return GetType(getASTContext().getFunctionType( ClangUtil::GetQualType(result_type), qual_type_args, proto_info)); diff --git a/lldb/test/API/lang/cpp/function-ref-qualifiers/Makefile b/lldb/test/API/lang/cpp/function-ref-qualifiers/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/function-ref-qualifiers/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/function-ref-qualifiers/TestCppFunctionQualifiers.py b/lldb/test/API/lang/cpp/function-ref-qualifiers/TestCppFunctionQualifiers.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/function-ref-qualifiers/TestCppFunctionQualifiers.py @@ -0,0 +1,39 @@ +""" +Tests that C++ expression evaluation can +disambiguate between rvalue and lvalue +reference-qualified functions. +""" + +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() + lldbutil.run_to_source_breakpoint(self, "Break here", lldb.SBFileSpec("main.cpp")) + + # const lvalue + self.expect_expr("const_foo.func()", result_type="uint32_t", result_value="0") + + # const rvalue + self.expect_expr("static_cast(Foo{}).func()", + result_type="int64_t", result_value="1") + + # non-const lvalue + self.expect_expr("foo.func()", result_type="uint32_t", result_value="2") + + # non-const rvalue + self.expect_expr("Foo{}.func()", result_type="int64_t", result_value="3") + + self.filecheck("target modules dump ast", __file__) + # CHECK: |-CXXMethodDecl {{.*}} func 'uint32_t () const &' + # CHECK-NEXT: | `-AsmLabelAttr {{.*}} + # CHECK-NEXT: |-CXXMethodDecl {{.*}} func 'int64_t () const &&' + # CHECK-NEXT: | `-AsmLabelAttr {{.*}} + # CHECK-NEXT: |-CXXMethodDecl {{.*}} func 'uint32_t () &' + # CHECK-NEXT: | `-AsmLabelAttr {{.*}} + # CHECK-NEXT: `-CXXMethodDecl {{.*}} func 'int64_t () &&' + # CHECK-NEXT: `-AsmLabelAttr {{.*}} diff --git a/lldb/test/API/lang/cpp/function-ref-qualifiers/main.cpp b/lldb/test/API/lang/cpp/function-ref-qualifiers/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/function-ref-qualifiers/main.cpp @@ -0,0 +1,19 @@ +#include +#include + +struct Foo { + uint32_t func() const & { return 0; } + int64_t func() const && { return 1; } + uint32_t func() & { return 2; } + int64_t func() && { return 3; } +}; + +int main() { + Foo foo; + const Foo const_foo; + auto res = foo.func() + const_foo.func() + Foo{}.func() + + static_cast(Foo{}).func(); + + std::puts("Break here"); + return res; +}