forked from OSchip/llvm-project
[lldb][TypeSystemClang] Honor DW_AT_rvalue_reference when creating C++ FunctionPrototypes
Currently funciton lookup in the expression evaluator fails to disambiguate member functions the are overloaded on lvalue/rvalue reference-qualifiers. This happens because we unconditionally set a `FunctionPrototype`s `ExtProtoInfo::RefQualifier` to `RQ_None`. We lose the ref-qualifiers in the synthesized AST and `clang::Sema` fails to pick a correct overload candidate. DWARF emits information about a function's ref-qualifiers in the form of a boolean `DW_AT_rvalue_reference` (for rvalues) and `DW_AT_reference` (for lvalues). This patch sets the `FunctionPrototype::ExtProtoInfo::RefQualifier` based on the DWARF attributes above. **Testing** * Added API test llvm/llvm-project issue #57866 Differential Revision: https://reviews.llvm.org/D134661
This commit is contained in:
parent
a6383bb51c
commit
60eb06be6d
|
@ -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 <map>
|
||||
#include <memory>
|
||||
|
@ -412,6 +412,12 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
|
|||
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 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
|
|||
|
||||
// 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;
|
||||
|
|
|
@ -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 @@ struct ParsedDWARFTypeAttributes {
|
|||
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
|
||||
|
|
|
@ -2168,11 +2168,10 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
|
|||
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 @@ TypeSystemClang::CreateFunctionType(const CompilerType &result_type,
|
|||
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));
|
||||
|
|
|
@ -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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
|
@ -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 const&&>(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 {{.*}}
|
|
@ -0,0 +1,19 @@
|
|||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
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 const &&>(Foo{}).func();
|
||||
|
||||
std::puts("Break here");
|
||||
return res;
|
||||
}
|
Loading…
Reference in New Issue