diff options
author | Pierre-Marie de Rodat <derodat@adacore.com> | 2017-06-21 11:24:51 +0000 |
---|---|---|
committer | Pierre-Marie de Rodat <pmderodat@gcc.gnu.org> | 2017-06-21 11:24:51 +0000 |
commit | ff9baa5f1c532a43d7d14a800f5a4a5c5757dca6 (patch) | |
tree | 7395ae997bed267b7d956093500e639f090e9fc8 /gcc/ada/gcc-interface | |
parent | a23ba8ccd0d3e16de01dfccf6304b9014e84f64f (diff) | |
download | gcc-ff9baa5f1c532a43d7d14a800f5a4a5c5757dca6.zip gcc-ff9baa5f1c532a43d7d14a800f5a4a5c5757dca6.tar.gz gcc-ff9baa5f1c532a43d7d14a800f5a4a5c5757dca6.tar.bz2 |
DWARF: make it possible to emit debug info for declarations only
The DWARF back-end used to systematically ignore file-scope function and
variable declarations. While this is justified in language like C/C++,
where such declarations can appear in several translation units and thus
bloat uselessly the debug info, this behavior is counter-productive in
languages with a well-defined module system. Specifically, it prevents
the description of imported entities, that belong to foreign languages,
making them unavailable from debuggers.
Take for instance:
package C_Binding is
function My_C_Function (I : Integer) return Integer;
pragma Import (C, My_C_Function, "my_c_function");
end C_Binding;
This makes available for Ada programs the C function "my_c_function"
under the following name: C_Binding.My_C_Function. When GCC compiles
it, though, it is represented as a FUNCTION_DECL node with DECL_EXTERNAL
set and a null DECL_INITIAL, which used to be discarded unconditionally
in the DWARF back-end.
This patch moves such filter from the DWARF back-end to the relevant
callers: passes.c:rest_of_decl_compilation and
godump.c:go_early_global_decl. It also This patch also updates the Ada
front-end to call debug hooks for functions such as in the above
example, so that we do generate debugging information for them.
gcc/
* dwarf2out.c (gen_decl_die): Remove the guard to skip file-scope
FUNCTION_DECL declarations.
(dwarf2out_early_global_decl): Remove the guard to skip FUNCTION_DECL
declarations.
(dwaf2out_decl): Likewise.
* godump.c (go_early_global_decl): Skip call to the real debug hook
for FUNCTION_DECL declarations.
* passes.c (rest_of_decl_compilation): Skip call to the
early_global_decl debug hook for FUNCTION_DECL declarations, unless
-fdump-go-spec is passed.
gcc/ada/
* gcc-interface/ada-tree.h (DECL_FUNCTION_IS_DEF): Update copyright
notice. New macro.
* gcc-interface/trans.c (Subprogram_Body_to_gnu): Tag the subprogram
as a definition.
(Compilation_Unit_to_gnu): Tag the elaboration procedure as a
definition.
* gcc-interface/decl.c (gnat_to_gnu_entity): Tag declarations of
imported subprograms for the current compilation unit as
definitions. Disable debug info for references to variables.
* gcc-interface/gigi.h (create_subprog_decl): Update declaration.
* gcc-interface/utils.c (gnat_pushdecl): Add external DECLs that are
not built-in functions to their binding scope.
(create_subprog_decl): Add a DEFINITION parameter. If it is true, tag
the function as a definition. Update all callers.
(gnat_write_global_declarations): Emit debug info for imported
functions. Filter out external variables for which debug info
is disabled.
gcc/testsuite/
* gnat.dg/debug11_pkg.adb, gnat.dg/debug11_pkg.ads,
gnat.dg/debug11_pkg2.ads: New testcase.
From-SVN: r249449
Diffstat (limited to 'gcc/ada/gcc-interface')
-rw-r--r-- | gcc/ada/gcc-interface/ada-tree.h | 7 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/decl.c | 19 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/gigi.h | 5 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/trans.c | 52 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/utils.c | 35 |
5 files changed, 80 insertions, 38 deletions
diff --git a/gcc/ada/gcc-interface/ada-tree.h b/gcc/ada/gcc-interface/ada-tree.h index a3d38b1..511a0bd 100644 --- a/gcc/ada/gcc-interface/ada-tree.h +++ b/gcc/ada/gcc-interface/ada-tree.h @@ -6,7 +6,7 @@ * * * C Header File * * * - * Copyright (C) 1992-2016, Free Software Foundation, Inc. * + * Copyright (C) 1992-2017, Free Software Foundation, Inc. * * * * GNAT is free software; you can redistribute it and/or modify it under * * terms of the GNU General Public License as published by the Free Soft- * @@ -463,6 +463,11 @@ do { \ a discriminant of a discriminated type without default expression. */ #define DECL_INVARIANT_P(NODE) DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) +/* Nonzero in a FUNCTION_DECL if this is a definition, i.e. if it was created + by a call to gnat_to_gnu_entity with definition set to True. */ +#define DECL_FUNCTION_IS_DEF(NODE) \ + DECL_LANG_FLAG_4 (FUNCTION_DECL_CHECK (NODE)) + /* Nonzero in a VAR_DECL if it is a temporary created to hold the return value of a function call or 'reference to a function call. */ #define DECL_RETURN_VALUE_P(NODE) DECL_LANG_FLAG_5 (VAR_DECL_CHECK (NODE)) diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index eab244e..83b9d07 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -1392,7 +1392,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) = create_var_decl (create_concat_name (gnat_entity, "ALIGN"), NULL_TREE, gnu_new_type, NULL_TREE, false, false, false, false, false, - true, debug_info_p, NULL, gnat_entity); + true, debug_info_p && definition, NULL, + gnat_entity); /* Initialize the aligned field if we have an initializer. */ if (gnu_expr) @@ -1441,7 +1442,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) NULL_TREE, gnu_type, gnu_expr, const_flag, Is_Public (gnat_entity), imported_p || !definition, static_flag, - volatile_flag, true, debug_info_p, + volatile_flag, true, + debug_info_p && definition, NULL, gnat_entity); gnu_expr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_unc_var); TREE_CONSTANT (gnu_expr) = 1; @@ -1492,8 +1494,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) = create_var_decl (gnu_entity_name, gnu_ext_name, gnu_type, gnu_expr, const_flag, Is_Public (gnat_entity), imported_p || !definition, static_flag, - volatile_flag, artificial_p, debug_info_p, - attr_list, gnat_entity, !renamed_obj); + volatile_flag, artificial_p, + debug_info_p && definition, attr_list, + gnat_entity, !renamed_obj); DECL_BY_REF_P (gnu_decl) = used_by_ref; DECL_POINTS_TO_READONLY_P (gnu_decl) = used_by_ref && inner_const_flag; DECL_CAN_NEVER_BE_NULL_P (gnu_decl) = Can_Never_Be_Null (gnat_entity); @@ -1545,8 +1548,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) = create_var_decl (gnu_entity_name, gnu_ext_name, gnu_type, gnu_expr, true, Is_Public (gnat_entity), !definition, static_flag, volatile_flag, - artificial_p, debug_info_p, attr_list, - gnat_entity, false); + artificial_p, debug_info_p && definition, + attr_list, gnat_entity, false); SET_DECL_CONST_CORRESPONDING_VAR (gnu_decl, gnu_corr_var); } @@ -4083,7 +4086,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) gnu_type, gnu_param_list, inline_status, public_flag, extern_flag, artificial_p, - debug_info_p, attr_list, gnat_entity); + debug_info_p, + definition && imported_p, attr_list, + gnat_entity); DECL_STUBBED_P (gnu_decl) = (Convention (gnat_entity) == Convention_Stubbed); diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index b1fb34a..0e25b61 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -720,6 +720,8 @@ extern tree create_label_decl (tree name, Node_Id gnat_node); DEBUG_INFO_P is true if we need to write debug information for it. + DEFINITION is true if the subprogram is to be considered as a definition. + ATTR_LIST is the list of attributes to be attached to the subprogram. GNAT_NODE is used for the position of the decl. */ @@ -728,7 +730,8 @@ extern tree create_subprog_decl (tree name, tree asm_name, tree type, enum inline_status_t inline_status, bool public_flag, bool extern_flag, bool artificial_p, bool debug_info_p, - struct attrib *attr_list, Node_Id gnat_node); + bool definition, struct attrib *attr_list, + Node_Id gnat_node); /* Given a subprogram declaration DECL, its assembler name and its type, finish constructing the subprogram declaration from ASM_NAME and TYPE. */ diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 2542626..79d0995 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -398,7 +398,7 @@ gigi (Node_Id gnat_root, = create_subprog_decl (get_identifier ("__gnat_malloc"), NULL_TREE, ftype, NULL_TREE, is_disabled, true, true, true, false, - NULL, Empty); + false, NULL, Empty); DECL_IS_MALLOC (malloc_decl) = 1; ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); @@ -406,7 +406,7 @@ gigi (Node_Id gnat_root, = create_subprog_decl (get_identifier ("__gnat_free"), NULL_TREE, ftype, NULL_TREE, is_disabled, true, true, true, false, - NULL, Empty); + false, NULL, Empty); ftype = build_function_type_list (ptr_type_node, ptr_type_node, sizetype, NULL_TREE); @@ -414,7 +414,7 @@ gigi (Node_Id gnat_root, = create_subprog_decl (get_identifier ("__gnat_realloc"), NULL_TREE, ftype, NULL_TREE, is_disabled, true, true, true, false, - NULL, Empty); + false, NULL, Empty); /* This is used for 64-bit multiplication with overflow checking. */ int64_type = gnat_type_for_size (64, 0); @@ -423,7 +423,7 @@ gigi (Node_Id gnat_root, build_function_type_list (int64_type, int64_type, int64_type, NULL_TREE), NULL_TREE, is_disabled, true, true, true, false, - NULL, Empty); + false, NULL, Empty); /* Name of the _Parent field in tagged record types. */ parent_name_id = get_identifier (Get_Name_String (Name_uParent)); @@ -446,21 +446,21 @@ gigi (Node_Id gnat_root, = create_subprog_decl (get_identifier ("system__soft_links__get_jmpbuf_address_soft"), NULL_TREE, build_function_type_list (jmpbuf_ptr_type, NULL_TREE), - NULL_TREE, is_disabled, true, true, true, false, NULL, Empty); + NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty); set_jmpbuf_decl = create_subprog_decl (get_identifier ("system__soft_links__set_jmpbuf_address_soft"), NULL_TREE, build_function_type_list (void_type_node, jmpbuf_ptr_type, NULL_TREE), - NULL_TREE, is_disabled, true, true, true, false, NULL, Empty); + NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty); get_excptr_decl = create_subprog_decl (get_identifier ("system__soft_links__get_gnat_exception"), NULL_TREE, build_function_type_list (build_pointer_type (except_type_node), NULL_TREE), - NULL_TREE, is_disabled, true, true, true, false, NULL, Empty); + NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty); not_handled_by_others_decl = get_identifier ("not_handled_by_others"); for (t = TYPE_FIELDS (except_type_node); t; t = DECL_CHAIN (t)) @@ -478,7 +478,7 @@ gigi (Node_Id gnat_root, (get_identifier ("__builtin_setjmp"), NULL_TREE, build_function_type_list (integer_type_node, jmpbuf_ptr_type, NULL_TREE), - NULL_TREE, is_disabled, true, true, true, false, NULL, Empty); + NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty); DECL_BUILT_IN_CLASS (setjmp_decl) = BUILT_IN_NORMAL; DECL_FUNCTION_CODE (setjmp_decl) = BUILT_IN_SETJMP; @@ -488,7 +488,7 @@ gigi (Node_Id gnat_root, = create_subprog_decl (get_identifier ("__builtin_update_setjmp_buf"), NULL_TREE, build_function_type_list (void_type_node, jmpbuf_ptr_type, NULL_TREE), - NULL_TREE, is_disabled, true, true, true, false, NULL, Empty); + NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty); DECL_BUILT_IN_CLASS (update_setjmp_buf_decl) = BUILT_IN_NORMAL; DECL_FUNCTION_CODE (update_setjmp_buf_decl) = BUILT_IN_UPDATE_SETJMP_BUF; @@ -500,14 +500,14 @@ gigi (Node_Id gnat_root, raise_nodefer_decl = create_subprog_decl (get_identifier ("__gnat_raise_nodefer_with_msg"), NULL_TREE, ftype, - NULL_TREE, is_disabled, true, true, true, false, NULL, Empty); + NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty); set_exception_parameter_decl = create_subprog_decl (get_identifier ("__gnat_set_exception_parameter"), NULL_TREE, build_function_type_list (void_type_node, ptr_type_node, ptr_type_node, NULL_TREE), - NULL_TREE, is_disabled, true, true, true, false, NULL, Empty); + NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty); /* Hooks to call when entering/leaving an exception handler. */ ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); @@ -515,26 +515,30 @@ gigi (Node_Id gnat_root, begin_handler_decl = create_subprog_decl (get_identifier ("__gnat_begin_handler"), NULL_TREE, ftype, NULL_TREE, - is_disabled, true, true, true, false, NULL, Empty); + is_disabled, true, true, true, false, false, NULL, + Empty); /* __gnat_begin_handler is a dummy procedure. */ TREE_NOTHROW (begin_handler_decl) = 1; end_handler_decl = create_subprog_decl (get_identifier ("__gnat_end_handler"), NULL_TREE, ftype, NULL_TREE, - is_disabled, true, true, true, false, NULL, Empty); + is_disabled, true, true, true, false, false, NULL, + Empty); unhandled_except_decl = create_subprog_decl (get_identifier ("__gnat_unhandled_except_handler"), NULL_TREE, ftype, NULL_TREE, - is_disabled, true, true, true, false, NULL, Empty); + is_disabled, true, true, true, false, false, NULL, + Empty); /* Indicate that it never returns. */ ftype = build_qualified_type (ftype, TYPE_QUAL_VOLATILE); reraise_zcx_decl = create_subprog_decl (get_identifier ("__gnat_reraise_zcx"), NULL_TREE, ftype, NULL_TREE, - is_disabled, true, true, true, false, NULL, Empty); + is_disabled, true, true, true, false, false, NULL, + Empty); /* Dummy objects to materialize "others" and "all others" in the exception tables. These are exported by a-exexpr-gcc.adb, so see this unit for @@ -573,7 +577,8 @@ gigi (Node_Id gnat_root, tree decl = create_subprog_decl (get_identifier ("__gnat_last_chance_handler"), NULL_TREE, ftype, - NULL_TREE, is_disabled, true, true, true, false, NULL, Empty); + NULL_TREE, is_disabled, true, true, true, false, false, NULL, + Empty); for (i = 0; i < (int) ARRAY_SIZE (gnat_raise_decls); i++) gnat_raise_decls[i] = decl; } @@ -739,7 +744,7 @@ build_raise_check (int check, enum exception_info_kind kind) result = create_subprog_decl (get_identifier (Name_Buffer), NULL_TREE, ftype, NULL_TREE, is_disabled, true, true, true, false, - NULL, Empty); + false, NULL, Empty); return result; } @@ -3745,6 +3750,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node) = gnat_to_gnu_entity (gnat_subprog_id, NULL_TREE, Acts_As_Spec (gnat_node) && !present_gnu_tree (gnat_subprog_id)); + DECL_FUNCTION_IS_DEF (gnu_subprog_decl) = true; gnu_result_decl = DECL_RESULT (gnu_subprog_decl); gnu_subprog_type = TREE_TYPE (gnu_subprog_decl); gnu_cico_list = TYPE_CI_CO_LIST (gnu_subprog_type); @@ -5417,12 +5423,15 @@ Compilation_Unit_to_gnu (Node_Id gnat_node) const Entity_Id gnat_unit_entity = Defining_Entity (gnat_unit); Entity_Id gnat_entity; Node_Id gnat_pragma; - /* Make the decl for the elaboration procedure. */ + /* Make the decl for the elaboration procedure. Emit debug info for it, so + that users can break into their elaboration code in debuggers. Kludge: + don't consider it as a definition so that we have a line map for its body, + but no subprogram description in debug info. */ tree gnu_elab_proc_decl = create_subprog_decl (create_concat_name (gnat_unit_entity, body_p ? "elabb" : "elabs"), NULL_TREE, void_ftype, NULL_TREE, - is_disabled, true, false, true, true, NULL, gnat_unit); + is_disabled, true, false, true, true, false, NULL, gnat_unit); struct elab_info *info; vec_safe_push (gnu_elab_proc_stack, gnu_elab_proc_decl); @@ -6453,7 +6462,7 @@ gnat_to_gnu (Node_Id gnat_node) gnu_prefix = gnat_to_gnu (gnat_prefix); gnu_prefix = maybe_implicit_deref (gnu_prefix); } - + gnu_result = build_component_ref (gnu_prefix, gnu_field, (Nkind (Parent (gnat_node)) @@ -6484,7 +6493,8 @@ gnat_to_gnu (Node_Id gnat_node) (Entity (Prefix (gnat_node)), attr == Attr_Elab_Body ? "elabb" : "elabs"), NULL_TREE, void_ftype, NULL_TREE, is_disabled, - true, true, true, true, NULL, gnat_node); + true, true, true, true, false, NULL, + gnat_node); gnu_result = Attribute_to_gnu (gnat_node, &gnu_result_type, attr); } diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index b8c5d3d..9e65657 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -763,11 +763,13 @@ gnat_pushdecl (tree decl, Node_Id gnat_node) if (!(TREE_CODE (decl) == TYPE_DECL && TREE_CODE (TREE_TYPE (decl)) == UNCONSTRAINED_ARRAY_TYPE)) { - if (DECL_EXTERNAL (decl)) - { - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)) - vec_safe_push (builtin_decls, decl); - } + /* External declarations must go to the binding level they belong to. + This will make corresponding imported entities are available in the + debugger at the proper time. */ + if (DECL_EXTERNAL (decl) + && TREE_CODE (decl) == FUNCTION_DECL + && DECL_BUILT_IN (decl)) + vec_safe_push (builtin_decls, decl); else if (global_bindings_p ()) vec_safe_push (global_decls, decl); else @@ -3189,6 +3191,8 @@ create_label_decl (tree name, Node_Id gnat_node) DEBUG_INFO_P is true if we need to write debug information for it. + DEFINITION is true if the subprogram is to be considered as a definition. + ATTR_LIST is the list of attributes to be attached to the subprogram. GNAT_NODE is used for the position of the decl. */ @@ -3197,7 +3201,8 @@ tree create_subprog_decl (tree name, tree asm_name, tree type, tree param_decl_list, enum inline_status_t inline_status, bool public_flag, bool extern_flag, bool artificial_p, bool debug_info_p, - struct attrib *attr_list, Node_Id gnat_node) + bool definition, struct attrib *attr_list, + Node_Id gnat_node) { tree subprog_decl = build_decl (input_location, FUNCTION_DECL, name, type); DECL_ARGUMENTS (subprog_decl) = param_decl_list; @@ -3208,6 +3213,8 @@ create_subprog_decl (tree name, tree asm_name, tree type, tree param_decl_list, if (!debug_info_p) DECL_IGNORED_P (subprog_decl) = 1; + if (definition) + DECL_FUNCTION_IS_DEF (subprog_decl) = 1; switch (inline_status) { @@ -5523,10 +5530,22 @@ gnat_write_global_declarations (void) if (TREE_CODE (iter) == TYPE_DECL && !DECL_IGNORED_P (iter)) debug_hooks->type_decl (iter, false); + /* Output imported functions. */ + FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter) + if (TREE_CODE (iter) == FUNCTION_DECL + && DECL_EXTERNAL (iter) + && DECL_INITIAL (iter) == NULL + && !DECL_IGNORED_P (iter) + && DECL_FUNCTION_IS_DEF (iter)) + debug_hooks->early_global_decl (iter); + /* Then output the global variables. We need to do that after the debug - information for global types is emitted so that they are finalized. */ + information for global types is emitted so that they are finalized. Skip + external global variables, unless we need to emit debug info for them: + this is useful for imported variables, for instance. */ FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter) - if (TREE_CODE (iter) == VAR_DECL) + if (TREE_CODE (iter) == VAR_DECL + && (!DECL_EXTERNAL (iter) || !DECL_IGNORED_P (iter))) rest_of_decl_compilation (iter, true, 0); /* Output the imported modules/declarations. In GNAT, these are only |