[Lldb-commits] [lldb] r359140 - Fix infinite recursion when calling C++ template functions

Frederic Riss via lldb-commits lldb-commits at lists.llvm.org
Wed Apr 24 14:04:24 PDT 2019


Author: friss
Date: Wed Apr 24 14:04:23 2019
New Revision: 359140

URL: http://llvm.org/viewvc/llvm-project?rev=359140&view=rev
Log:
Fix infinite recursion when calling C++ template functions

Summary:
When we encounter a templated function in the debug information, we
were creating an AST that looked like this:

FunctionTemplateDecl 0x12980ab90 <<invalid sloc>> <invalid sloc> foo<int>
|-TemplateTypeParmDecl 0x12980aad0 <<invalid sloc>> <invalid sloc> class depth 0 index 0 T
|-FunctionDecl 0x12980aa30 <<invalid sloc>> <invalid sloc> foo<int> 'int (int)' extern
| |-TemplateArgument type 'int'
| `-ParmVarDecl 0x12980a998 <<invalid sloc>> <invalid sloc> t1 'int'
`-FunctionDecl 0x12980aa30 <<invalid sloc>> <invalid sloc> foo<int> 'int (int)' extern
  |-TemplateArgument type 'int'
  `-ParmVarDecl 0x12980a998 <<invalid sloc>> <invalid sloc> t1 'int'

Note that the FunctionTemplateDecl has 2 children which are identical (as
in have the same address). This is not what Clang is doing:

FunctionTemplateDecl 0x7f89d206c6f8 </tmp/template.cpp:1:1, line:4:1> line:2:5 foo
|-TemplateTypeParmDecl 0x7f89d206c4a8 <line:1:10, col:19> col:19 referenced typename depth 0 index 0 T
|-FunctionDecl 0x7f89d206c660 <line:2:1, line:4:1> line:2:5 foo 'int (T)'
| `-ParmVarDecl 0x7f89d206c570 <col:9, col:11> col:11 t1 'T'
`-FunctionDecl 0x7f89d206cb60 <line:2:1, line:4:1> line:2:5 used foo 'int (int)'
  |-TemplateArgument type 'int'
  `-ParmVarDecl 0x7f89d206ca68 <col:9, col:11> col:11 t1 'int':'int'

The 2 chidlren are different and actually repesent different things: the first
one is the unspecialized version and the second one is specialized. (Just looking
at the names shows another major difference which is that we create the parent
with a name of "foo<int>" when it should be just "foo".)

The fact that we have those 2 identical children confuses the ClangImporter
and generates an infinite recursion (reported in https://llvm.org/pr41473).
We cannot create the unspecialized version as the debug information doesn't
contain a mapping from the template parameters to their use in the prototype.

This patch just creates 2 different FunctionDecls for those 2 children of the
FunctionTemplateDecl. This avoids the infinite recursion and allows us to
call functions. As the XFAILs in the added test show, we've still got issues
in our handling of templates. I believe they are mostly centered on the fact
that we create do not register "foo" as a template, but "foo<int>". This is
a bigger change that will need changes to the debug information generation.
I believe this change makes sense on its own.

Reviewers: shafik, clayborg, jingham

Subscribers: aprantl, javed.absar, kristof.beyls, lldb-commits

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

Added:
    lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/
    lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/TestTemplateFunctions.py
    lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/main.cpp
Modified:
    lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Added: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/Makefile?rev=359140&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/Makefile Wed Apr 24 14:04:23 2019
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/TestTemplateFunctions.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/TestTemplateFunctions.py?rev=359140&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/TestTemplateFunctions.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/TestTemplateFunctions.py Wed Apr 24 14:04:23 2019
@@ -0,0 +1,30 @@
+"""
+Test that we can call C++ template fucntions.
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TemplateFunctionsTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def do_test_template_function(self, add_cast):
+        self.build()
+        (_, _, thread, _) = lldbutil.run_to_name_breakpoint(self, "main")
+        frame = thread.GetSelectedFrame()
+        expr = "foo(42)"
+        if add_cast:
+            expr = "(int)" + expr
+        expr_result = frame.EvaluateExpression(expr)
+        self.assertTrue(expr_result.IsValid())
+        self.assertEqual(expr_result.GetValue(), "42")
+
+    def test_template_function_with_cast(self):
+        self.do_test_template_function(True)
+
+    @expectedFailureAll(debug_info=["dwarf", "gmodules"])
+    def test_template_function_without_cast(self):
+        self.do_test_template_function(False)

Added: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/main.cpp?rev=359140&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/template-function/main.cpp Wed Apr 24 14:04:23 2019
@@ -0,0 +1,16 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+template<typename T>
+int foo(T t1) {
+        return int(t1);
+}
+
+int main() {
+        return foo(42);
+}

Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp?rev=359140&r1=359139&r2=359140&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp (original)
+++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp Wed Apr 24 14:04:23 2019
@@ -1590,6 +1590,7 @@ TypeSP DWARFASTParserClang::ParseTypeFro
 
           if (!type_handled) {
             clang::FunctionDecl *function_decl = nullptr;
+            clang::FunctionDecl *template_function_decl = nullptr;
 
             if (abstract_origin_die_form.IsValid()) {
               DWARFDIE abs_die =
@@ -1617,10 +1618,14 @@ TypeSP DWARFASTParserClang::ParseTypeFro
               if (has_template_params) {
                 ClangASTContext::TemplateParameterInfos template_param_infos;
                 ParseTemplateParameterInfos(die, template_param_infos);
+                template_function_decl = m_ast.CreateFunctionDeclaration(
+                    ignore_containing_context ? m_ast.GetTranslationUnitDecl()
+                                              : containing_decl_ctx,
+                    type_name_cstr, clang_type, storage, is_inline);
                 clang::FunctionTemplateDecl *func_template_decl =
                     m_ast.CreateFunctionTemplateDecl(
-                        containing_decl_ctx, function_decl, type_name_cstr,
-                        template_param_infos);
+                        containing_decl_ctx, template_function_decl,
+                        type_name_cstr, template_param_infos);
                 m_ast.CreateFunctionTemplateSpecializationInfo(
                     function_decl, func_template_decl, template_param_infos);
               }
@@ -1630,10 +1635,15 @@ TypeSP DWARFASTParserClang::ParseTypeFro
               if (function_decl) {
                 LinkDeclContextToDIE(function_decl, die);
 
-                if (!function_param_decls.empty())
+                if (!function_param_decls.empty()) {
                   m_ast.SetFunctionParameters(function_decl,
                                               &function_param_decls.front(),
                                               function_param_decls.size());
+                  if (template_function_decl)
+                    m_ast.SetFunctionParameters(template_function_decl,
+                                                &function_param_decls.front(),
+                                                function_param_decls.size());
+                }
 
                 ClangASTMetadata metadata;
                 metadata.SetUserID(die.GetID());




More information about the lldb-commits mailing list