Hi! DWARF5 introduced DW_AT_export_symbols that may be preset on DW_TAG_namespace or DW_TAG_{structure,union,class}_type to signalize inline or anonymous namespaces or anonymous structures/unions/classes.
What we were emitting instead is an implicit DW_TAG_imported_module in the outer namespace. The following patch changes nothing for -gdwarf-4 and below with -gstrict-dwarf, for -gdwarf-4 and below -gno-strict-dwarf it just adds DW_AT_export_symbols to inline namespaces (so that interested consumers can find out it is inline namespace, but consumers not knowing about DW_AT_export_symbols still have the implicit DW_TAG_imported_module). In that mode, no changes for anonymous namespaces, because those are already easily detectable by the consumers (missing DW_AT_name). For -gdwarf-5 it emits DW_AT_export_symbols on both inline namespaces and anonymous namespaces and doesn't emit the implicit DW_TAG_imported_module, which is shorter. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? This patch doesn't do anything about anon struct/union/class, I've tried to handle it, the problem is that ANON_AGGR_TYPE_P flag is set too late, after the debug hook adds the type DIE. Any thoughts on how to handle that? And I wonder what is the counterpart of ANON_AGGR_TYPE_P in the C FE, CCing Marek on that. 2017-07-21 Jakub Jelinek <ja...@redhat.com> * debug.h (struct gcc_debug_hooks): Add IMPLICIT argument to imported_module_or_decl hook. (debug_nothing_tree_tree_tree_bool): Remove. (debug_nothing_tree_tree_tree_bool_bool): New declaration. * debug.c (do_nothing_debug_hooks): Use debug_nothing_tree_tree_tree_bool_bool instead of debug_nothing_tree_tree_tree_bool. * vmsdbgout.c (vmsdbg_debug_hooks): Likewise. * dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise. * sdbout.c (sdb_debug_hooks): Likewise. * dwarf2out.c (dwarf2_lineno_debug_hooks): Likewise. (gen_namespace_die): Add DW_AT_export_symbols attribute if langhook wants it. (dwarf2out_imported_module_or_decl): Add IMPLICIT argument, if true, -gdwarf-5 and decl will have DW_AT_export_symbols attribute, don't add anything. cp/ * cp-objcp-common.c (cp_decl_dwarf_attribute): Handle DW_AT_export_symbols. * name-lookup.c (emit_debug_info_using_namespace): Add IMPLICIT argument, pass it through to the debug hook. (finish_namespace_using_directive): Adjust emit_debug_info_using_namespace caller. (push_namespace): Likewise. Call it after setting DECL_NAMESPACE_INLINE_P. (cp_emit_debug_info_for_using): Pass false as new argument to the imported_module_or_decl debug hook. fortran/ * trans-decl.c (gfc_trans_use_stmts): Pass false as new argument to the imported_module_or_decl debug hook. ada/ * gcc-interface/utils.c (gnat_write_global_declarations): Pass false as new argument to the imported_module_or_decl debug hook. testsuite/ * g++.dg/debug/dwarf2/inline-ns-1.C: New test. * g++.dg/debug/dwarf2/inline-ns-2.C: New test. --- gcc/debug.h.jj 2017-02-18 17:11:18.000000000 +0100 +++ gcc/debug.h 2017-07-21 12:19:09.486576092 +0200 @@ -145,7 +145,8 @@ struct gcc_debug_hooks /* Debug information for imported modules and declarations. */ void (* imported_module_or_decl) (tree decl, tree name, - tree context, bool child); + tree context, bool child, + bool implicit); /* DECL is an inline function, whose body is present, but which is not being output at this point. */ @@ -206,7 +207,8 @@ extern void debug_nothing_int_int (unsig extern void debug_nothing_tree (tree); extern void debug_nothing_tree_tree (tree, tree); extern void debug_nothing_tree_int (tree, int); -extern void debug_nothing_tree_tree_tree_bool (tree, tree, tree, bool); +extern void debug_nothing_tree_tree_tree_bool_bool (tree, tree, tree, + bool, bool); extern bool debug_true_const_tree (const_tree); extern void debug_nothing_rtx_insn (rtx_insn *); extern void debug_nothing_rtx_code_label (rtx_code_label *); --- gcc/debug.c.jj 2017-02-18 17:11:18.000000000 +0100 +++ gcc/debug.c 2017-07-21 11:53:45.452383785 +0200 @@ -47,7 +47,7 @@ const struct gcc_debug_hooks do_nothing_ debug_nothing_tree, /* early_global_decl */ debug_nothing_tree, /* late_global_decl */ debug_nothing_tree_int, /* type_decl */ - debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ + debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ debug_nothing_rtx_code_label, /* label */ @@ -80,10 +80,11 @@ debug_nothing_tree_tree (tree t1 ATTRIBU } void -debug_nothing_tree_tree_tree_bool (tree t1 ATTRIBUTE_UNUSED, - tree t2 ATTRIBUTE_UNUSED, - tree t3 ATTRIBUTE_UNUSED, - bool b1 ATTRIBUTE_UNUSED) +debug_nothing_tree_tree_tree_bool_bool (tree t1 ATTRIBUTE_UNUSED, + tree t2 ATTRIBUTE_UNUSED, + tree t3 ATTRIBUTE_UNUSED, + bool b1 ATTRIBUTE_UNUSED, + bool b2 ATTRIBUTE_UNUSED) { } --- gcc/vmsdbgout.c.jj 2017-02-18 17:11:18.000000000 +0100 +++ gcc/vmsdbgout.c 2017-07-21 11:54:50.757609629 +0200 @@ -197,7 +197,7 @@ const struct gcc_debug_hooks vmsdbg_debu vmsdbgout_early_global_decl, vmsdbgout_late_global_decl, vmsdbgout_type_decl, /* type_decl */ - debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ + debug_nothing_tree_tree_tree_bool_bool, /* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ vmsdbgout_abstract_function, debug_nothing_rtx_code_label, /* label */ --- gcc/dbxout.c.jj 2017-07-21 10:28:12.000000000 +0200 +++ gcc/dbxout.c 2017-07-21 11:54:03.115174403 +0200 @@ -371,7 +371,7 @@ const struct gcc_debug_hooks dbx_debug_h dbxout_early_global_decl, /* early_global_decl */ dbxout_late_global_decl, /* late_global_decl */ dbxout_type_decl, /* type_decl */ - debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ + debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ debug_nothing_rtx_code_label, /* label */ @@ -411,7 +411,7 @@ const struct gcc_debug_hooks xcoff_debug dbxout_early_global_decl, /* early_global_decl */ dbxout_late_global_decl, /* late_global_decl */ dbxout_type_decl, /* type_decl */ - debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ + debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ debug_nothing_rtx_code_label, /* label */ --- gcc/sdbout.c.jj 2017-02-18 17:11:18.000000000 +0100 +++ gcc/sdbout.c 2017-07-21 11:54:32.259828909 +0200 @@ -301,7 +301,7 @@ const struct gcc_debug_hooks sdb_debug_h sdbout_early_global_decl, /* early_global_decl */ sdbout_late_global_decl, /* late_global_decl */ sdbout_symbol, /* type_decl */ - debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ + debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ sdbout_label, /* label */ --- gcc/dwarf2out.c.jj 2017-07-21 10:28:12.659136982 +0200 +++ gcc/dwarf2out.c 2017-07-21 12:01:14.052065893 +0200 @@ -2680,7 +2680,7 @@ static bool dwarf2out_ignore_block (cons static void dwarf2out_early_global_decl (tree); static void dwarf2out_late_global_decl (tree); static void dwarf2out_type_decl (tree, int); -static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool); +static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool, bool); static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree, dw_die_ref); static void dwarf2out_abstract_function (tree); @@ -2764,7 +2764,7 @@ const struct gcc_debug_hooks dwarf2_line debug_nothing_tree, /* early_global_decl */ debug_nothing_tree, /* late_global_decl */ debug_nothing_tree_int, /* type_decl */ - debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ + debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */ debug_nothing_tree, /* deferred_inline_function */ debug_nothing_tree, /* outlining_inline_function */ debug_nothing_rtx_code_label, /* label */ @@ -25166,6 +25172,11 @@ gen_namespace_die (tree decl, dw_die_ref add_AT_die_ref (namespace_die, DW_AT_import, origin_die); equate_decl_number_to_die (decl, namespace_die); } + if ((dwarf_version >= 5 || !dwarf_strict) + && lang_hooks.decls.decl_dwarf_attribute (decl, + DW_AT_export_symbols) == 1) + add_AT_flag (namespace_die, DW_AT_export_symbols, 1); + /* Bypass dwarf2_name's check for DECL_NAMELESS. */ if (want_pubnames ()) add_pubname_string (lang_hooks.dwarf_name (decl, 1), namespace_die); @@ -25579,11 +25590,13 @@ dwarf2out_imported_module_or_decl_1 (tre /* Output debug information for imported module or decl DECL. NAME is non-NULL name in context if the decl has been renamed. CHILD is true if decl is one of the renamed decls as part of - importing whole module. */ + importing whole module. + IMPLICIT is set if this hook is called for an implicit import + such as inline namespace. */ static void dwarf2out_imported_module_or_decl (tree decl, tree name, tree context, - bool child) + bool child, bool implicit) { /* dw_die_ref at_import_die; */ dw_die_ref scope_die; @@ -25593,6 +25606,16 @@ dwarf2out_imported_module_or_decl (tree gcc_assert (decl); + /* For DWARF5, just DW_AT_export_symbols on the DW_TAG_namespace + should be enough, for DWARF4 and older even if we emit as extension + DW_AT_export_symbols add the implicit DW_TAG_imported_module anyway + for the benefit of consumers unaware of DW_AT_export_symbols. */ + if (implicit + && dwarf_version >= 5 + && lang_hooks.decls.decl_dwarf_attribute (decl, + DW_AT_export_symbols) == 1) + return; + set_early_dwarf s; /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs. --- gcc/cp/cp-objcp-common.c.jj 2017-07-19 14:01:18.866064325 +0200 +++ gcc/cp/cp-objcp-common.c 2017-07-21 12:18:28.031066986 +0200 @@ -212,6 +212,13 @@ cp_decl_dwarf_attribute (const_tree decl } break; + case DW_AT_export_symbols: + if (TREE_CODE (decl) == NAMESPACE_DECL + && (DECL_NAMESPACE_INLINE_P (decl) + || (DECL_NAME (decl) == NULL_TREE && dwarf_version >= 5))) + return 1; + break; + default: break; } --- gcc/cp/name-lookup.c.jj 2017-07-19 14:01:18.887064085 +0200 +++ gcc/cp/name-lookup.c 2017-07-21 12:06:27.525349847 +0200 @@ -6045,11 +6045,12 @@ add_using_namespace (vec<tree, va_gc> *& /* Tell the debug system of a using directive. */ static void -emit_debug_info_using_namespace (tree from, tree target) +emit_debug_info_using_namespace (tree from, tree target, bool implicit) { /* Emit debugging info. */ tree context = from != global_namespace ? from : NULL_TREE; - debug_hooks->imported_module_or_decl (target, NULL_TREE, context, false); + debug_hooks->imported_module_or_decl (target, NULL_TREE, context, false, + implicit); } /* Process a namespace-scope using directive. */ @@ -6064,7 +6065,7 @@ finish_namespace_using_directive (tree t add_using_namespace (DECL_NAMESPACE_USING (current_namespace), ORIGINAL_NAMESPACE (target)); emit_debug_info_using_namespace (current_namespace, - ORIGINAL_NAMESPACE (target)); + ORIGINAL_NAMESPACE (target), false); if (attribs == error_mark_node) return; @@ -6223,14 +6224,14 @@ push_namespace (tree name, bool make_inl else if (TREE_PUBLIC (current_namespace)) TREE_PUBLIC (ns) = 1; - if (name == anon_identifier || make_inline) - emit_debug_info_using_namespace (current_namespace, ns); - if (make_inline) { DECL_NAMESPACE_INLINE_P (ns) = true; vec_safe_push (DECL_NAMESPACE_INLINEES (current_namespace), ns); } + + if (name == anon_identifier || make_inline) + emit_debug_info_using_namespace (current_namespace, ns, true); } } @@ -6358,8 +6359,8 @@ cp_emit_debug_info_for_using (tree t, tr if (building_stmt_list_p ()) add_stmt (build_stmt (input_location, USING_STMT, fn)); else - debug_hooks->imported_module_or_decl (fn, - NULL_TREE, context, false); + debug_hooks->imported_module_or_decl (fn, NULL_TREE, context, + false, false); } } } --- gcc/fortran/trans-decl.c.jj 2017-05-12 14:34:55.000000000 +0200 +++ gcc/fortran/trans-decl.c 2017-07-21 12:11:53.917733772 +0200 @@ -4875,7 +4875,7 @@ gfc_trans_use_stmts (gfc_namespace * ns) (*debug_hooks->imported_module_or_decl) (entry->namespace_decl, NULL_TREE, ns->proc_name->backend_decl, - false); + false, false); for (rent = use_stmt->rename; rent; rent = rent->next) { tree decl, local_name; @@ -4952,7 +4952,8 @@ gfc_trans_use_stmts (gfc_namespace * ns) gfc_set_backend_locus (&rent->where); (*debug_hooks->imported_module_or_decl) (decl, local_name, ns->proc_name->backend_decl, - !use_stmt->only_flag); + !use_stmt->only_flag, + false); } } } --- gcc/ada/gcc-interface/utils.c.jj 2017-06-21 16:53:37.000000000 +0200 +++ gcc/ada/gcc-interface/utils.c 2017-07-21 12:12:22.569394503 +0200 @@ -5553,7 +5553,7 @@ gnat_write_global_declarations (void) FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter) if (TREE_CODE (iter) == IMPORTED_DECL && !DECL_IGNORED_P (iter)) debug_hooks->imported_module_or_decl (iter, DECL_NAME (iter), - DECL_CONTEXT (iter), 0); + DECL_CONTEXT (iter), false, false); } /* ************************************************************************ --- gcc/testsuite/g++.dg/debug/dwarf2/inline-ns-1.C.jj 2017-07-21 13:36:41.589158999 +0200 +++ gcc/testsuite/g++.dg/debug/dwarf2/inline-ns-1.C 2017-07-21 13:51:34.353524052 +0200 @@ -0,0 +1,23 @@ +// { dg-options "-O2 -gdwarf-4 -dA -gno-strict-dwarf" } +// { dg-final { scan-assembler-times " DW_AT_export_symbols" 1 } } +// { dg-final { scan-assembler-times "DIE \\(\[^\n\r\]*\\) DW_TAG_imported_module" 2 } } + +namespace A +{ + int i = 5; + inline namespace B + { + int j = 6; + namespace C + { + int k = 7; + }; + }; +}; +int l = A::i + A::j + A::C::k; +int m = A::i + A::B::j + A::B::C::k; +namespace +{ + int n = 8; +}; +int o = n; --- gcc/testsuite/g++.dg/debug/dwarf2/inline-ns-2.C.jj 2017-07-21 13:40:16.689595957 +0200 +++ gcc/testsuite/g++.dg/debug/dwarf2/inline-ns-2.C 2017-07-21 13:52:20.043981081 +0200 @@ -0,0 +1,23 @@ +// { dg-options "-O2 -gdwarf-5 -dA" } +// { dg-final { scan-assembler-times " DW_AT_export_symbols" 2 } } +// { dg-final { scan-assembler-not "DIE \\(\[^\n\r\]*\\) DW_TAG_imported_module" } } + +namespace A +{ + int i = 5; + inline namespace B + { + int j = 6; + namespace C + { + int k = 7; + }; + }; +}; +int l = A::i + A::j + A::C::k; +int m = A::i + A::B::j + A::B::C::k; +namespace +{ + int n = 8; +}; +int o = n; Jakub