[Lldb-commits] [lldb] 9e2715a - [lldb] Remove template parameters from FunctionTemplateDecl names

via lldb-commits lldb-commits at lists.llvm.org
Tue Mar 17 11:00:51 PDT 2020


Author: shafik
Date: 2020-03-17T11:00:23-07:00
New Revision: 9e2715aaacaa3087933b5575d23563751b54843b

URL: https://github.com/llvm/llvm-project/commit/9e2715aaacaa3087933b5575d23563751b54843b
DIFF: https://github.com/llvm/llvm-project/commit/9e2715aaacaa3087933b5575d23563751b54843b.diff

LOG: [lldb] Remove template parameters from FunctionTemplateDecl names

Fix to get the AST we generate for function templates closer to what clang generates and expects.
We fix which FuntionDecl we are passing to CreateFunctionTemplateSpecializationInfo and we strip
template parameters from the name when creating the FunctionDecl and FunctionTemplateDecl.

These two fixes together fix asserts and ambiguous lookup issues for several cases which are added to the already existing small function template test.
This fixes issues with overloads, overloads and ADL, variadic function templates and templated operator overloads.

Differential Revision: https://reviews.llvm.org/D75761

Added: 
    

Modified: 
    lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
    lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py
    lldb/test/API/lang/cpp/template-function/main.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index b1007d257cc7..8838888b2e23 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -35,6 +35,8 @@
 #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"
@@ -1167,12 +1169,22 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
       }
 
       if (!function_decl) {
+        const char *name = attrs.name.GetCString();
+
+        // We currently generate function templates with template parameters in
+        // their name. In order to get closer to the AST that clang generates
+        // we want to strip these from the name when creating the AST.
+        if (attrs.mangled_name) {
+          llvm::ItaniumPartialDemangler D;
+          if (!D.partialDemangle(attrs.mangled_name))
+            name = D.getFunctionBaseName(nullptr, nullptr);
+        }
+
         // We just have a function that isn't part of a class
         function_decl = m_ast.CreateFunctionDeclaration(
             ignore_containing_context ? m_ast.GetTranslationUnitDecl()
                                       : containing_decl_ctx,
-            attrs.name.GetCString(), clang_type, attrs.storage,
-            attrs.is_inline);
+            name, clang_type, attrs.storage, attrs.is_inline);
 
         if (has_template_params) {
           TypeSystemClang::TemplateParameterInfos template_param_infos;
@@ -1180,14 +1192,14 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
           template_function_decl = m_ast.CreateFunctionDeclaration(
               ignore_containing_context ? m_ast.GetTranslationUnitDecl()
                                         : containing_decl_ctx,
-              attrs.name.GetCString(), clang_type, attrs.storage,
-              attrs.is_inline);
+              name, clang_type, attrs.storage, attrs.is_inline);
+
           clang::FunctionTemplateDecl *func_template_decl =
-              m_ast.CreateFunctionTemplateDecl(
-                  containing_decl_ctx, template_function_decl,
-                  attrs.name.GetCString(), template_param_infos);
+              m_ast.CreateFunctionTemplateDecl(containing_decl_ctx,
+                                               template_function_decl, name,
+                                               template_param_infos);
           m_ast.CreateFunctionTemplateSpecializationInfo(
-              function_decl, func_template_decl, template_param_infos);
+              template_function_decl, func_template_decl, template_param_infos);
         }
 
         lldbassert(function_decl);

diff  --git a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py
index 6c9a0ac35f4f..0e74185546e8 100644
--- a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py
+++ b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py
@@ -13,14 +13,40 @@ class TemplateFunctionsTestCase(TestBase):
 
     def do_test_template_function(self, add_cast):
         self.build()
-        (_, _, thread, _) = lldbutil.run_to_name_breakpoint(self, "main")
-        frame = thread.GetSelectedFrame()
-        expr = "foo(42)"
+        lldbutil.run_to_source_breakpoint(self, '// break here',
+                lldb.SBFileSpec("main.cpp", False))
+
         if add_cast:
-            expr = "(int)" + expr
-        expr_result = frame.EvaluateExpression(expr)
-        self.assertTrue(expr_result.IsValid())
-        self.assertEqual(expr_result.GetValue(), "42")
+          self.expect_expr("(int) foo(42)", result_type="int", result_value="42")
+        else:
+          self.expect("expr b1 <=> b2",  error=True, substrs=["warning: <user expression 0>:1:4: '<=>' is a single token in C++20; add a space to avoid a change in behavior"])
+
+          self.expect_expr("foo(42)", result_type="int", result_value="42")
+
+          # overload with template case
+          self.expect_expr("h(10)", result_type="int", result_value="10")
+
+          # ADL lookup case
+          self.expect_expr("f(A::C{})", result_type="int", result_value="4")
+
+          # ADL lookup but no overload
+          self.expect_expr("g(A::C{})", result_type="int", result_value="4")
+
+          # variadic function cases
+          self.expect_expr("var(1)", result_type="int", result_value="10")
+          self.expect_expr("var(1, 2)", result_type="int", result_value="10")
+
+          # Overloaded templated operator case
+          self.expect_expr("b1 > b2", result_type="bool", result_value="true")
+          self.expect_expr("b1 >> b2", result_type="bool", result_value="true")
+          self.expect_expr("b1 << b2", result_type="bool", result_value="true")
+          self.expect_expr("b1 == b2", result_type="bool", result_value="true")
+
+          # Overloaded operator case
+          self.expect_expr("d1 > d2", result_type="bool", result_value="true")
+          self.expect_expr("d1 >> d2", result_type="bool", result_value="true")
+          self.expect_expr("d1 << d2", result_type="bool", result_value="true")
+          self.expect_expr("d1 == d2", result_type="bool", result_value="true")
 
     @skipIfWindows
     def test_template_function_with_cast(self):

diff  --git a/lldb/test/API/lang/cpp/template-function/main.cpp b/lldb/test/API/lang/cpp/template-function/main.cpp
index c0fbc5cee668..729638147eb3 100644
--- a/lldb/test/API/lang/cpp/template-function/main.cpp
+++ b/lldb/test/API/lang/cpp/template-function/main.cpp
@@ -3,6 +3,66 @@ int foo(T t1) {
         return int(t1);
 }
 
+// Some cases to cover ADL, we have two cases:
+//
+// - f which will have a overload in the global namespace if unqualified lookup
+// find f(int) and f(T) is found via ADL.
+//
+// - g which does not have an overload in the global namespace.
+namespace A {
+struct C {};
+
+template <typename T> int f(T) { return 4; }
+
+template <typename T> int g(T) { return 4; }
+} // namespace A
+
+// Meant to overload A::f(T) which may be found via ADL
+int f(int) { return 1; }
+
+// Regular overloaded functions case h(T) and h(double).
+template <class T> int h(T x) { return x; }
+int h(double d) { return 5; }
+
+template <class... Us> int var(Us... pargs) { return 10; }
+
+// Having the templated overloaded operators in a namespace effects the
+// mangled name generated in the IR e.g. _ZltRK1BS1_ Vs _ZN1AltERKNS_1BES2_
+// One will be in the symbol table but the other won't. This results in a
+// 
diff erent code path that will result in CPlusPlusNameParser being used.
+// This allows us to cover that code as well.
+namespace A {
+template <typename T> bool operator<(const T &, const T &) { return true; }
+
+template <typename T> bool operator>(const T &, const T &) { return true; }
+
+template <typename T> bool operator<<(const T &, const T &) { return true; }
+
+template <typename T> bool operator>>(const T &, const T &) { return true; }
+
+template <typename T> bool operator==(const T &, const T &) { return true; }
+
+struct B {};
+} // namespace A
+
+struct D {};
+
+// Make sure we cover more straight forward cases as well.
+bool operator<(const D &, const D &) { return true; }
+bool operator>(const D &, const D &) { return true; }
+bool operator>>(const D &, const D &) { return true; }
+bool operator<<(const D &, const D &) { return true; }
+bool operator==(const D &, const D &) { return true; }
+
 int main() {
-        return foo(42);
+  A::B b1;
+  A::B b2;
+  D d1;
+  D d2;
+
+  bool result_b = b1 < b2 && b1 << b2 && b1 == b2 && b1 > b2 && b1 >> b2;
+  bool result_c = d1 < d2 && d1 << d2 && d1 == d2 && d1 > d2 && d1 >> d2;
+
+  return foo(42) + result_b + result_c + f(A::C{}) + g(A::C{}) + h(10) + h(1.) +
+         var(1) + var(1, 2); // break here
 }


        


More information about the lldb-commits mailing list