+2017-06-21 Pierre-Marie de Rodat <derodat@adacore.com>
+
+ * 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.
+
2017-06-21 Marc Glisse <marc.glisse@inria.fr>
* config/i386/i386.c (struct builtin_isa): New field pure_p.
+2017-06-21 Pierre-Marie de Rodat <derodat@adacore.com>
+
+ * 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.
+
2017-06-15 Nicolas Boulenguez <nicolas.boulenguez@free.fr>
PR ada/81105
* *
* 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- *
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))
= 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)
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;
= 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);
= 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);
}
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);
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. */
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. */
= 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);
= 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);
= 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);
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));
= 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))
(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;
= 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;
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);
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
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;
}
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;
}
= 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);
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);
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))
(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);
}
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
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. */
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;
if (!debug_info_p)
DECL_IGNORED_P (subprog_decl) = 1;
+ if (definition)
+ DECL_FUNCTION_IS_DEF (subprog_decl) = 1;
switch (inline_status)
{
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
break;
case FUNCTION_DECL:
- /* Don't output any DIEs to represent mere function declarations,
- unless they are class members or explicit block externs. */
- if (DECL_INITIAL (decl_or_origin) == NULL_TREE
- && DECL_FILE_SCOPE_P (decl_or_origin)
- && (current_function_decl == NULL_TREE
- || DECL_ARTIFICIAL (decl_or_origin)))
- break;
-
#if 0
/* FIXME */
/* This doesn't work because the C frontend sets DECL_ABSTRACT_ORIGIN
tree save_fndecl = current_function_decl;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
- /* No cfun means the symbol has no body, so there's nothing
- to emit. */
- if (!DECL_STRUCT_FUNCTION (decl))
- goto early_decl_exit;
-
/* For nested functions, make sure we have DIEs for the parents first
so that all nested DIEs are generated at the proper scope in the
first shot. */
if (TREE_CODE (decl) == FUNCTION_DECL)
current_function_decl = save_fndecl;
}
- early_decl_exit:
symtab->global_info_ready = save;
}
return;
case FUNCTION_DECL:
- /* What we would really like to do here is to filter out all mere
- file-scope declarations of file-scope functions which are never
- referenced later within this translation unit (and keep all of ones
- that *are* referenced later on) but we aren't clairvoyant, so we have
- no idea which functions will be referenced in the future (i.e. later
- on within the current translation unit). So here we just ignore all
- file-scope function declarations which are not also definitions. If
- and when the debugger needs to know something about these functions,
- it will have to hunt around and find the DWARF information associated
- with the definition of the function.
-
- We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
- nodes represent definitions and which ones represent mere
- declarations. We have to check DECL_INITIAL instead. That's because
- the C front-end supports some weird semantics for "extern inline"
- function definitions. These can get inlined within the current
- translation unit (and thus, we need to generate Dwarf info for their
- abstract instances so that the Dwarf info for the concrete inlined
- instances can have something to refer to) but the compiler never
- generates any out-of-lines instances of such things (despite the fact
- that they *are* definitions).
-
- The important point is that the C front-end marks these "extern
- inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
- them anyway. Note that the C++ front-end also plays some similar games
- for inline function definitions appearing within include files which
- also contain `#pragma interface' pragmas.
-
- If we are called from dwarf2out_abstract_function output a DIE
- anyway. We can end up here this way with early inlining and LTO
- where the inlined function is output in a different LTRANS unit
- or not at all. */
- if (DECL_INITIAL (decl) == NULL_TREE
- && ! DECL_ABSTRACT_P (decl))
- return;
-
/* If we're a nested function, initially use a parent of NULL; if we're
a plain function, this will be fixed up in decls_for_scope. If
we're a method, it will be ignored, since we already have a DIE. */
go_early_global_decl (tree decl)
{
go_decl (decl);
- real_debug_hooks->early_global_decl (decl);
+ if (TREE_CODE (decl) != FUNCTION_DECL || DECL_STRUCT_FUNCTION (decl) != NULL)
+ real_debug_hooks->early_global_decl (decl);
}
/* A global variable decl. */
finalize_compilation_unit (and by consequence, locally scoped
symbols), or by rest_of_type_compilation below.
- Also, pick up function prototypes, which will be mostly ignored
- by the different early_global_decl() hooks, but will at least be
- used by Go's hijack of the debug_hooks to implement
- -fdump-go-spec. */
+ For Go's hijack of the debug_hooks to implement -fdump-go-spec, pick up
+ function prototypes. Go's debug_hooks will not forward them to the
+ wrapped hooks. */
if (!in_lto_p
&& (TREE_CODE (decl) != FUNCTION_DECL
/* This will pick up function prototypes with no bodies,
which are not visible in finalize_compilation_unit()
while iterating with FOR_EACH_*_FUNCTION through the
symbol table. */
- || !DECL_SAVED_TREE (decl))
+ || (flag_dump_go_spec != NULL
+ && !DECL_SAVED_TREE (decl)
+ && DECL_STRUCT_FUNCTION (decl) == NULL))
/* We need to check both decl_function_context and
current_function_decl here to make sure local extern
+2017-06-21 Pierre-Marie de Rodat <derodat@adacore.com>
+
+ * gnat.dg/debug11_pkg.adb, gnat.dg/debug11_pkg.ads,
+ gnat.dg/debug11_pkg2.ads: New testcase.
+
2017-06-21 Marc Glisse <marc.glisse@inria.fr>
* gcc.target/i386/getround.c: New file.
--- /dev/null
+-- { dg-options "-cargs -g -dA -margs" }
+-- { dg-final { scan-assembler "local_imported_func" } }
+-- { dg-final { scan-assembler "local_imported_var" } }
+-- { dg-final { scan-assembler "global_imported_func" } }
+-- { dg-final { scan-assembler "global_imported_var" } }
+-- { dg-final { scan-assembler-not "foreign_imported_func" } }
+-- { dg-final { scan-assembler-not "foreign_imported_var" } }
+
+with Debug11_Pkg2;
+
+package body Debug11_Pkg is
+
+ procedure Dummy is
+ Local_Imported_Var : Integer;
+ pragma Import (C, Local_Imported_Var, "imported_var");
+
+ function Local_Imported_Func return Integer;
+ pragma Import (C, Local_Imported_Func, "imported_func");
+ begin
+ Local_Imported_Var := Local_Imported_Func;
+ Global_Imported_Var := Global_Imported_Func;
+ Debug11_Pkg2.Foreign_Imported_Var :=
+ Debug11_Pkg2.Foreign_Imported_Func;
+ end Dummy;
+
+end Debug11_Pkg;
--- /dev/null
+package Debug11_Pkg is
+
+ Global_Imported_Var : Integer;
+ pragma Import (C, Global_Imported_Var, "imported_var");
+
+ function Global_Imported_Func return Integer;
+ pragma Import (C, Global_Imported_Func, "imported_func");
+
+ procedure Dummy;
+
+end Debug11_Pkg;
--- /dev/null
+package Debug11_Pkg2 is
+
+ Foreign_Imported_Var : Integer;
+ pragma Import (C, Foreign_Imported_Var, "imported_var");
+
+ function Foreign_Imported_Func return Integer;
+ pragma Import (C, Foreign_Imported_Func, "imported_func");
+
+end Debug11_Pkg2;