Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -818,6 +818,38 @@ return type_sp; } +static clang::Optional +StripTemplateParameters(llvm::StringRef Name) { + // We are looking for template parameters to strip from Name. e.g. + // + // operator< + // + // We look for > at the end but if it does not contain any < then we + // have something like operator>>. We check for the operator<=> case. + if (!Name.endswith(">") || Name.count("<") == 0 || Name.endswith("<=>")) + return {}; + + // How many < until we have the start of the template parameters. + size_t NumLeftAnglesToSkip = 1; + + // If we have operator<=> then we need to skip its < as well. + NumLeftAnglesToSkip += Name.count("<=>"); + + size_t RightAngleCount = Name.count('>'); + size_t LeftAngleCount = Name.count('<'); + + // If we have more < than > we have operator< or operator<< + // we to account for their < as well. + if (LeftAngleCount > RightAngleCount) + NumLeftAnglesToSkip += LeftAngleCount - RightAngleCount; + + size_t StartOfTemplate = 0; + while (NumLeftAnglesToSkip--) + StartOfTemplate = Name.find('<', StartOfTemplate) + 1; + + return Name.substr(0, StartOfTemplate - 1); +} + TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs) { Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | @@ -1167,11 +1199,20 @@ } if (!function_decl) { + llvm::StringRef name_without_template_params_ref = + attrs.name.GetStringRef(); + if (clang::Optional stripped_name = + StripTemplateParameters(attrs.name.GetStringRef())) + name_without_template_params_ref = *stripped_name; + + std::string name_without_template_params = + name_without_template_params_ref.str(); + // 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, + name_without_template_params.c_str(), clang_type, attrs.storage, attrs.is_inline); if (has_template_params) { @@ -1180,14 +1221,15 @@ template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, + name_without_template_params.c_str(), 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); + name_without_template_params.c_str(), 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); Index: lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py =================================================================== --- lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py +++ lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py @@ -13,14 +13,54 @@ def do_test_template_function(self, add_cast): self.build() - (_, _, thread, _) = lldbutil.run_to_name_breakpoint(self, "main") - frame = thread.GetSelectedFrame() - expr = "foo(42)" + (self.target, self.process, _, bkpt) = 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)", + substrs=['(int)', '= 42']) + else: + self.expect("expr foo(42)", + substrs=['(int)', '= 42']) + + self.expect("expr h(10)", + substrs=['(int)', '= 10']) + + self.expect("expr f(A::C{})", + substrs=['(int)', '= 4']) + + self.expect("expr g(A::C{})", + substrs=['(int)', '= 4']) + + self.expect("expr var(1)", + substrs=['(int)', '= 10']) + + self.expect("expr var(1,2)", + substrs=['(int)', '= 10']) + + self.expect("expr b1 > b2", + substrs=['(bool)', '= true']) + + self.expect("expr b1 >> b2", + substrs=['(bool)', '= true']) + + self.expect("expr b1 << b2", + substrs=['(bool)', '= true']) + + self.expect("expr b1 == b2", + substrs=['(bool)', '= true']) + + self.expect("expr c1 > c2", + substrs=['(bool)', '= true']) + + self.expect("expr c1 >> c2", + substrs=['(bool)', '= true']) + + self.expect("expr c1 << c2", + substrs=['(bool)', '= true']) + + self.expect("expr c1 == c2", + substrs=['(bool)', '= true']) @skipIfWindows def test_template_function_with_cast(self): Index: lldb/test/API/lang/cpp/template-function/main.cpp =================================================================== --- lldb/test/API/lang/cpp/template-function/main.cpp +++ lldb/test/API/lang/cpp/template-function/main.cpp @@ -3,6 +3,67 @@ return int(t1); } +// Some cases to cover ADL +namespace A { +struct C {}; + +template int f(T) { return 4; } + +template int g(T) { return 4; } +} // namespace A + +int f(int) { return 1; } + +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 C {}; + +// Make sure we cover more straight forward cases as well. +bool operator<(const C &, const C &) { return true; } +bool operator>(const C &, const C &) { return true; } +bool operator>>(const C &, const C &) { return true; } +bool operator<<(const C &, const C &) { return true; } +bool operator==(const C &, const C &) { return true; } + int main() { - return foo(42); + A::B b1; + A::B b2; + C c1; + C c2; + + bool result_b = b1 < b2 && b1 << b2 && b1 == b2 && b1 > b2 && b1 >> b2; + bool result_c = c1 < c2 && c1 << c2 && c1 == c2 && c1 > c2 && c1 >> c2; + + return foo(42) + result_b + result_c + + // ADL lookup case, + f(A::C{}) + + // ADL lookup but no overload + g(A::C{}) + + // overload with template + h(10) + h(1.) + + // variadic function + var(1) + var(1, 2); // break here }