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 @@ -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 @@ } 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 @@ 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 --- a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py +++ b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py @@ -13,14 +13,40 @@ 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: :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 --- a/lldb/test/API/lang/cpp/template-function/main.cpp +++ b/lldb/test/API/lang/cpp/template-function/main.cpp @@ -3,6 +3,66 @@ 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 int f(T) { return 4; } + +template 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 int h(T x) { return x; } +int h(double d) { return 5; } + +template 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 +// different code path that will result in CPlusPlusNameParser being used. +// This allows us to cover that code as well. +namespace A { +template bool operator<(const T &, const T &) { return true; } + +template bool operator>(const T &, const T &) { return true; } + +template bool operator<<(const T &, const T &) { return true; } + +template bool operator>>(const T &, const T &) { return true; } + +template 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 }