[Lldb-commits] [lldb] 60eb06b - [lldb][TypeSystemClang] Honor DW_AT_rvalue_reference when creating C++ FunctionPrototypes

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Tue Sep 27 10:04:09 PDT 2022


Author: Michael Buch
Date: 2022-09-27T18:03:23+01:00
New Revision: 60eb06be6d23e3c5fd80113143784aac0d962965

URL: https://github.com/llvm/llvm-project/commit/60eb06be6d23e3c5fd80113143784aac0d962965
DIFF: https://github.com/llvm/llvm-project/commit/60eb06be6d23e3c5fd80113143784aac0d962965.diff

LOG: [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

Added: 
    lldb/test/API/lang/cpp/function-ref-qualifiers/Makefile
    lldb/test/API/lang/cpp/function-ref-qualifiers/TestCppFunctionQualifiers.py
    lldb/test/API/lang/cpp/function-ref-qualifiers/main.cpp

Modified: 
    lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
    lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 9fe9b2e25a2f8..25f2a37cbab5d 100644
--- 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 <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;

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index 735665328fd50..a8640b4a56938 100644
--- 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 @@ 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

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 6164b978f2f24..7e0a19c6b8bf1 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -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));

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 7f25a6df548fb..ff8e12e821d12 100644
--- 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 @@ class TypeSystemClang : public TypeSystem {
       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/test/API/lang/cpp/function-ref-qualifiers/Makefile b/lldb/test/API/lang/cpp/function-ref-qualifiers/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /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
index 0000000000000..0016ede4937e2
--- /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 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 {{.*}}

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
index 0000000000000..70f3a63eb9e64
--- /dev/null
+++ b/lldb/test/API/lang/cpp/function-ref-qualifiers/main.cpp
@@ -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;
+}


        


More information about the lldb-commits mailing list