Index: lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -326,9 +326,11 @@ else ptr_qual_type = Ctx.getPointerType(expr_qual_type); - result_decl = - VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), - result_ptr_id, ptr_qual_type, nullptr, SC_Static); + TypeSourceInfo *tsi = Ctx.getTrivialTypeSourceInfo( + ptr_qual_type, last_expr->getSourceRange().getBegin()); + + result_decl = VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), + result_ptr_id, ptr_qual_type, tsi, SC_Static); if (!result_decl) return false; @@ -342,9 +344,10 @@ } else { IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result"); - result_decl = - VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), &result_id, - expr_qual_type, nullptr, SC_Static); + TypeSourceInfo *tsi = Ctx.getTrivialTypeSourceInfo( + expr_qual_type, last_expr->getSourceRange().getBegin()); + result_decl = VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), + &result_id, expr_qual_type, tsi, SC_Static); if (!result_decl) return false; Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -400,7 +400,8 @@ break; case DW_AT_type: - type = form_value; + if (!type.IsValid()) + type = form_value; break; case DW_AT_virtuality: @@ -619,6 +620,12 @@ clang_type = m_ast.GetBasicType(eBasicTypeNullPtr); break; } + if (attrs.name == "auto") { + resolve_state = Type::ResolveState::Full; + clang::QualType t = m_ast.getASTContext().getAutoDeductType(); + clang_type = m_ast.GetType(t); + break; + } // Fall through to base type below in case we can handle the type // there... LLVM_FALLTHROUGH; @@ -905,6 +912,24 @@ return clang::CC_C; } +static void maybePropagateDeducedReturnType(clang::DeclContext *decl_ctx, + clang::ASTContext &ast, + CompilerType function_type) { + auto *function_decl = llvm::dyn_cast_or_null(decl_ctx); + + if (!function_decl) + return; + + if (!function_decl->getReturnType()->isUndeducedAutoType()) + return; + + if (TypeSystemClang *ts = llvm::dyn_cast_or_null( + function_type.GetTypeSystem())) + ast.adjustDeducedFunctionResultType( + function_decl, ClangUtil::GetQualType(ts->GetFunctionReturnType( + function_type.GetOpaqueQualType()))); +} + TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs) { Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); @@ -991,6 +1016,14 @@ return_clang_type, function_param_types.data(), function_param_types.size(), is_variadic, type_quals, calling_convention); + if (attrs.specification.IsValid()) { + DWARFDIE abs_die = attrs.specification.Reference(); + if (dwarf->ResolveType(abs_die)) { + maybePropagateDeducedReturnType(GetCachedClangDeclContextForDIE(abs_die), + m_ast.getASTContext(), clang_type); + } + } + if (attrs.name) { bool type_handled = false; if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { @@ -1322,6 +1355,21 @@ } } } + + // If a function has an auto return type we need to find the definition since + // that will have the deduced return type and adjust the FunctionDecl to + // reflect this. + if (func_type && func_type->GetName() == "auto") { + if (TypeSP ret_type = dwarf->FindTypeForAutoReturnForDIE( + die, ConstString(attrs.mangled_name))) { + return_clang_type = ret_type->GetForwardCompilerType(); + if (auto *function_decl = llvm::dyn_cast_or_null( + GetCachedClangDeclContextForDIE(die))) + m_ast.getASTContext().adjustDeducedFunctionResultType( + function_decl, ClangUtil::GetQualType(return_clang_type)); + } + } + return std::make_shared( die.GetID(), dwarf, attrs.name, llvm::None, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Full); Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -432,6 +432,9 @@ lldb_private::ConstString type_name, bool must_be_implementation); + lldb::TypeSP FindTypeForAutoReturnForDIE(const DWARFDIE &die, + lldb_private::ConstString name); + lldb_private::Symbol * GetObjCClassSymbol(lldb_private::ConstString objc_class_name); Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2756,6 +2756,59 @@ return type_sp; } +lldb::TypeSP +SymbolFileDWARF::FindTypeForAutoReturnForDIE(const DWARFDIE &die, + lldb_private::ConstString name) { + if (!name) + return {}; + + DWARFDIE other_die; + if (m_objfile_sp) { + Symtab *symtab = m_objfile_sp->GetSymtab(); + if (symtab) { + std::vector symbol_indexes; + symtab->FindAllSymbolsWithNameAndType( + name, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, + symbol_indexes); + + DWARFUnit *unit = die.GetCU(); + DWARFCompileUnit *dcu = llvm::cast_or_null(unit); + + if (!dcu) + return {}; + + for (size_t index = 0; index < symbol_indexes.size() && !other_die; + ++index) { + other_die = dcu->LookupAddress( + symtab->SymbolAtIndex(symbol_indexes[index])->GetFileAddress()); + } + } + } + + if (!other_die) + return {}; + + Type *resolved_type = ResolveType(other_die, false, true); + + if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED) + return {}; + + ParsedDWARFTypeAttributes attrs(other_die); + Type *func_type = nullptr; + + if (attrs.specification.IsValid()) + if (attrs.type.IsValid()) { + func_type = ResolveTypeUID(attrs.type.Reference(), true); + + if (!func_type || func_type == DIE_IS_BEING_PARSED) + return {}; + + return func_type->shared_from_this(); + } + + return {}; +} + // This function helps to ensure that the declaration contexts match for two // different DIEs. Often times debug information will refer to a forward // declaration of a type (the equivalent of "struct my_struct;". There will Index: lldb/test/API/lang/cpp/auto_return/Makefile =================================================================== --- /dev/null +++ lldb/test/API/lang/cpp/auto_return/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp other.cpp +CXXFLAGS_EXTRAS := -std=c++17 + +include Makefile.rules Index: lldb/test/API/lang/cpp/auto_return/TestCppAutoReturn.py =================================================================== --- /dev/null +++ lldb/test/API/lang/cpp/auto_return/TestCppAutoReturn.py @@ -0,0 +1,43 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestCppAutoReturn(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp")) + + self.expect_expr("globalAutoRetFun()", result_type="int", result_value="10") + self.expect_expr("globalAutoRetFunFwdDecl()", result_type="int", result_value="11") + + self.expect_expr("swumfGlobal.f1()", result_type="float", result_value="1") + self.expect_expr("swumfGlobal.f2()", result_type="int", result_value="1212") + + self.expect_expr("swumfLocal.f1()", result_type="float", result_value="1") + self.expect_expr("swumfLocal.f2()", result_type="int", result_value="1212") + + self.expect_expr("globalLambda()", result_type="Dummy", result_children=[ValueCheck(type="int", name="x", value="8")]) + + self.expect_expr("NS::namespaceFunc()", result_type="unsigned int", result_value="1") + self.expect_expr("NS::namespaceLambda()", result_type="unsigned int", result_value="2") + self.expect_expr("NS::StructInNamespace{}.f()", result_type="unsigned int", result_value="3") + + self.expect_expr("tsful.f()", result_type="unsigned long", result_value="4") + + self.expect_expr("w.f()", result_type="int", result_value="1") + + lldbutil.run_to_source_breakpoint(self, "// break also here", lldb.SBFileSpec("other.cpp")) + self.expect_expr("w.f()", result_type="int", result_value="1") + + + @skipIf + def FailingTest(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp")) + + ## rdar://92676775 + self.expect_expr("localLambda()", result_type="int", result_value="100") Index: lldb/test/API/lang/cpp/auto_return/main.cpp =================================================================== --- /dev/null +++ lldb/test/API/lang/cpp/auto_return/main.cpp @@ -0,0 +1,64 @@ +auto globalAutoRetFun() { return 10; } + +auto globalAutoRetFunFwdDecl(); +auto globalAutoRetFunFwdDecl() { return 11; } + +struct StructWithAutoMemFuns { + auto f1(); // Return type deduced out of line + auto f2() { return 1212; } // Return deduced inline +}; + +StructWithAutoMemFuns swumfGlobal; + +auto StructWithAutoMemFuns::f1() { return 1.f; } + +struct Dummy { + int x = 8; +}; + +auto globalLambda = []() { return Dummy{}; }; + +namespace NS { +auto namespaceFunc() { return 1u; } + +auto namespaceLambda = []() { return 2u; }; + +struct StructInNamespace { + auto f() { return 3u; } +}; +} // namespace NS + +template struct TempStruct { + auto f() { return static_cast(4); } +}; + +template using TSF = TempStruct; + +using TSFUL = TSF; + +void other(); + +namespace { +struct Wrapper { + auto f(); +}; + +auto Wrapper::f() { + auto x = [](int y) { return y; }; + return x(1); +} +} // namespace + +int main() { + StructWithAutoMemFuns swumfLocal; + TSFUL tsful; + + auto localLambda = []() { return 100; }; + + Wrapper w; + other(); + return globalLambda().x + globalAutoRetFun() + globalAutoRetFunFwdDecl() + + w.f() + swumfGlobal.f1() + swumfLocal.f2() + NS::namespaceFunc() + + NS::namespaceLambda() + NS::StructInNamespace{}.f() + tsful.f() + + localLambda(); // break here +} Index: lldb/test/API/lang/cpp/auto_return/other.cpp =================================================================== --- /dev/null +++ lldb/test/API/lang/cpp/auto_return/other.cpp @@ -0,0 +1,15 @@ +namespace { +struct Wrapper { + auto f(); +}; + +auto Wrapper::f() { + auto x = [](int y) { return y; }; + return x(2); +} +} // namespace + +void other() { + Wrapper w; + w.f(); // // break also here +} Index: lldb/test/Shell/SymbolFile/DWARF/x86/auto_return_symtab.s =================================================================== --- /dev/null +++ lldb/test/Shell/SymbolFile/DWARF/x86/auto_return_symtab.s @@ -0,0 +1,257 @@ +# This tests that lldb when using symbol table we are able to find the definition +# for an auto return function. + +# RUN: llvm-mc -triple x86_64-apple-macosx10.15.0 %s -filetype=obj > %t.o +# RUN: lldb-test symbols --dump-clang-ast %t.o | FileCheck %s + +# CHECK: CXXMethodDecl {{.*}} <> f 'int ()' + +# This was compiled from the following code: +# +# struct A { +# auto f(); +# }; +# +# auto A::f() { +# return 0; +# } +# +# Compiled using: +# +# -target x86_64-apple-macosx10.15.0 +# +# and edited to remove some uneeded sections. + + .section __TEXT,__text,regular,pure_instructions + .globl __ZN1A1fEv ## -- Begin function _ZN1A1fEv + .p2align 4, 0x90 +__ZN1A1fEv: ## @_ZN1A1fEv +Lfunc_begin0: + .cfi_startproc +## %bb.0: ## %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movq %rdi, -8(%rbp) +Ltmp0: + xorl %eax, %eax + popq %rbp + retq +Ltmp1: +Lfunc_end0: + .cfi_endproc + ## -- End function + .section __DWARF,__debug_abbrev,regular,debug +Lsection_abbrev: + .byte 1 ## Abbreviation Code + .byte 17 ## DW_TAG_compile_unit + .byte 1 ## DW_CHILDREN_yes + .byte 37 ## DW_AT_producer + .byte 14 ## DW_FORM_strp + .byte 19 ## DW_AT_language + .byte 5 ## DW_FORM_data2 + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .ascii "\202|" ## DW_AT_LLVM_sysroot + .byte 14 ## DW_FORM_strp + .ascii "\357\177" ## DW_AT_APPLE_sdk + .byte 14 ## DW_FORM_strp + .byte 16 ## DW_AT_stmt_list + .byte 23 ## DW_FORM_sec_offset + .byte 27 ## DW_AT_comp_dir + .byte 14 ## DW_FORM_strp + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 2 ## Abbreviation Code + .byte 19 ## DW_TAG_structure_type + .byte 1 ## DW_CHILDREN_yes + .byte 54 ## DW_AT_calling_convention + .byte 11 ## DW_FORM_data1 + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 11 ## DW_AT_byte_size + .byte 11 ## DW_FORM_data1 + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 3 ## Abbreviation Code + .byte 46 ## DW_TAG_subprogram + .byte 1 ## DW_CHILDREN_yes + .byte 110 ## DW_AT_linkage_name + .byte 14 ## DW_FORM_strp + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 60 ## DW_AT_declaration + .byte 25 ## DW_FORM_flag_present + .byte 63 ## DW_AT_external + .byte 25 ## DW_FORM_flag_present + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 4 ## Abbreviation Code + .byte 5 ## DW_TAG_formal_parameter + .byte 0 ## DW_CHILDREN_no + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 52 ## DW_AT_artificial + .byte 25 ## DW_FORM_flag_present + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 5 ## Abbreviation Code + .byte 59 ## DW_TAG_unspecified_type + .byte 0 ## DW_CHILDREN_no + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 6 ## Abbreviation Code + .byte 15 ## DW_TAG_pointer_type + .byte 0 ## DW_CHILDREN_no + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 7 ## Abbreviation Code + .byte 46 ## DW_TAG_subprogram + .byte 1 ## DW_CHILDREN_yes + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .byte 64 ## DW_AT_frame_base + .byte 24 ## DW_FORM_exprloc + .byte 100 ## DW_AT_object_pointer + .byte 19 ## DW_FORM_ref4 + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 71 ## DW_AT_specification + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 8 ## Abbreviation Code + .byte 5 ## DW_TAG_formal_parameter + .byte 0 ## DW_CHILDREN_no + .byte 2 ## DW_AT_location + .byte 24 ## DW_FORM_exprloc + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 52 ## DW_AT_artificial + .byte 25 ## DW_FORM_flag_present + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 9 ## Abbreviation Code + .byte 36 ## DW_TAG_base_type + .byte 0 ## DW_CHILDREN_no + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 62 ## DW_AT_encoding + .byte 11 ## DW_FORM_data1 + .byte 11 ## DW_AT_byte_size + .byte 11 ## DW_FORM_data1 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 0 ## EOM(3) + .section __DWARF,__debug_info,regular,debug +Lsection_info: +Lcu_begin0: +.set Lset0, Ldebug_info_end0-Ldebug_info_start0 ## Length of Unit + .long Lset0 +Ldebug_info_start0: + .short 4 ## DWARF version number +.set Lset1, Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section + .long Lset1 + .byte 8 ## Address Size (in bytes) + .byte 1 ## Abbrev [1] 0xb:0x86 DW_TAG_compile_unit + .long 0 ## DW_AT_producer + .short 33 ## DW_AT_language + .long 105 ## DW_AT_name + .long 129 ## DW_AT_LLVM_sysroot + .long 185 ## DW_AT_APPLE_sdk +.set Lset2, Lline_table_start0-Lsection_line ## DW_AT_stmt_list + .long Lset2 + .long 200 ## DW_AT_comp_dir + .quad Lfunc_begin0 ## DW_AT_low_pc +.set Lset3, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc + .long Lset3 + .byte 2 ## Abbrev [2] 0x32:0x1f DW_TAG_structure_type + .byte 5 ## DW_AT_calling_convention + .long 219 ## DW_AT_name + .byte 1 ## DW_AT_byte_size + .byte 1 ## DW_AT_decl_file + .byte 1 ## DW_AT_decl_line + .byte 3 ## Abbrev [3] 0x3b:0x15 DW_TAG_subprogram + .long 221 ## DW_AT_linkage_name + .long 231 ## DW_AT_name + .byte 1 ## DW_AT_decl_file + .byte 2 ## DW_AT_decl_line + .long 81 ## DW_AT_type + ## DW_AT_declaration + ## DW_AT_external + .byte 4 ## Abbrev [4] 0x4a:0x5 DW_TAG_formal_parameter + .long 86 ## DW_AT_type + ## DW_AT_artificial + .byte 0 ## End Of Children Mark + .byte 0 ## End Of Children Mark + .byte 5 ## Abbrev [5] 0x51:0x5 DW_TAG_unspecified_type + .long 233 ## DW_AT_name + .byte 6 ## Abbrev [6] 0x56:0x5 DW_TAG_pointer_type + .long 50 ## DW_AT_type + .byte 7 ## Abbrev [7] 0x5b:0x29 DW_TAG_subprogram + .quad Lfunc_begin0 ## DW_AT_low_pc +.set Lset4, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc + .long Lset4 + .byte 1 ## DW_AT_frame_base + .byte 86 + .long 119 ## DW_AT_object_pointer + .long 132 ## DW_AT_type + .byte 5 ## DW_AT_decl_line + .long 59 ## DW_AT_specification + .byte 8 ## Abbrev [8] 0x77:0xc DW_TAG_formal_parameter + .byte 2 ## DW_AT_location + .byte 145 + .byte 120 + .long 242 ## DW_AT_name + .long 139 ## DW_AT_type + ## DW_AT_artificial + .byte 0 ## End Of Children Mark + .byte 9 ## Abbrev [9] 0x84:0x7 DW_TAG_base_type + .long 238 ## DW_AT_name + .byte 5 ## DW_AT_encoding + .byte 4 ## DW_AT_byte_size + .byte 6 ## Abbrev [6] 0x8b:0x5 DW_TAG_pointer_type + .long 50 ## DW_AT_type + .byte 0 ## End Of Children Mark +Ldebug_info_end0: + .section __DWARF,__debug_str,regular,debug +Linfo_string: + .asciz "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 18c3c7784975700ae463bb461487d46e74324a66)" ## string offset=0 + .asciz "auto_return_minimum.cpp" ## string offset=105 + .asciz "/Library/Developer/CommandLineTools/SDKs/MacOSX11.3.sdk" ## string offset=129 + .asciz "MacOSX11.3.sdk" ## string offset=185 + .asciz "/Users/shafik/code" ## string offset=200 + .asciz "A" ## string offset=219 + .asciz "_ZN1A1fEv" ## string offset=221 + .asciz "f" ## string offset=231 + .asciz "auto" ## string offset=233 + .asciz "int" ## string offset=238 + .asciz "this" ## string offset=242 +Lsection_line: +Lline_table_start0: