From: Pierre-Marie de Rodat Date: Wed, 22 Jul 2015 13:30:57 +0000 (+0200) Subject: [Ada] Add support for subprogram renamings X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=22cee43f9af76fc4c10c3d4018a9ada6d7c5c1a5;p=binutils-gdb.git [Ada] Add support for subprogram renamings Consider the following declaration: function Foo (I : Integer) return Integer renames Pack.Bar; As Foo is not materialized as a routine whose name is derived from Foo, GDB currently cannot use it: (gdb) print foo(0) No definition of "foo" in current context. However, compilers can emit DW_TAG_imported_declaration in order to materialize the fact that Foo is actually another name for Pack.Bar. This commit enhances the DWARF reader to record global renamings (it used to put global ones in a static block) and enhances the Ada engine to leverage this information during symbol lookup. gdb/ChangeLog: * ada-lang.c: Include namespace.h (aux_add_nonlocal_symbols): Fix a function name in comment. (ada_add_block_renamings): New. (add_nonlocal_symbols): Add global renamings handling. (ada_lookup_symbol_list_worker): Move the symbol lookup part to... (ada_add_all_symbols): ... this new function. (ada_add_block_symbols): Try to match the input name against the "using directives list", perform a recursive symbol lookup on the matched declarations. * block.h (struct block): Move the_namespace to top-level as namespace_info. Remove the language_specific field. (BLOCK_NAMESPACE): Update access to the namespace_info field. * buildsym.h (using_directives): Rename into... (local_using_directives): ... this. (global_using_directives): New. (struct context_stack): Rename the using_directives field into local_using_directives. * buildsym.c (finish_block_internal): Deal with the proper using directives repository (local or global). (prepare_for_building): Reset local_using_directives. Assert that there is no pending global using directive. (reset_symtab_globals): Reset global_using_directives and local_using_directives. (end_symtab_get_static_block): Don't ignore symtabs that have only using directives. (push_context): Update references to local_using_directives. (buildsym_init): Do not reset using_directives. * cp-support.c: Include namespace.h. * cp-support.h (struct using_direct): Move to namespace.h. (cp_add_using_directives): Move to namespace.h. * cp-namespace.c: Include namespace.h (cp_add_using_directive): Move to namespace.c, rename it to add_using_directive, add a "using_directives" argument and use it as the pending using directives repository. All callers updated. * dwarf2read.c (using_directives): New. (read_import_statement): Call using_directives. (read_func_scope): Update references to local_using_directives. (read_lexical_block_scope): Likewise. (read_namespace): Update the heading comment, call using_directives. * namespace.h: New file. * namespace.c: New file. * Makefile.in (SFILES): Add namespace.c. (COMMON_OBS): Add namespace.o gdb/testsuite/ChangeLog: * gdb.ada/fun_renaming.exp: New testcase. * gdb.ada/fun_renaming/fun_renaming.adb: New file. * gdb.ada/fun_renaming/pack.adb: New file. * gdb.ada/fun_renaming/pack.ads: New file. Tested on x86_64-linux. Support for this in GCC is in the pipeline: see . --- diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 596ddeb9ee5..d8974d9077f 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -862,6 +862,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ memrange.c mi/mi-common.c \ + namespace.c \ objc-lang.c \ objfiles.c osabi.c observer.c osdata.c \ opencl-lang.c \ @@ -1025,7 +1026,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ charset.o continuations.o corelow.o disasm.o dummy-frame.o dfp.o \ source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \ block.o symtab.o psymtab.o symfile.o symfile-debug.o symmisc.o \ - linespec.o dictionary.o \ + linespec.o dictionary.o namespace.o \ location.o infcall.o \ infcmd.o infrun.o \ expprint.o environ.o stack.o thread.o \ diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 9f9be642f00..1fa65244808 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -53,6 +53,7 @@ #include "stack.h" #include "gdb_vecs.h" #include "typeprint.h" +#include "namespace.h" #include "psymtab.h" #include "value.h" @@ -108,6 +109,9 @@ static void ada_add_block_symbols (struct obstack *, const struct block *, const char *, domain_enum, struct objfile *, int); +static void ada_add_all_symbols (struct obstack *, const struct block *, + const char *, domain_enum, int, int *); + static int is_nonfunction (struct block_symbol *, int); static void add_defn_to_vec (struct obstack *, struct symbol *, @@ -5289,7 +5293,7 @@ struct match_data int found_sym; }; -/* A callback for add_matching_symbols that adds SYM, found in BLOCK, +/* A callback for add_nonlocal_symbols that adds SYM, found in BLOCK, to a list of symbols. DATA0 is a pointer to a struct match_data * containing the obstack that collects the symbol list, the file that SYM must come from, a flag indicating whether a non-argument symbol has @@ -5329,6 +5333,62 @@ aux_add_nonlocal_symbols (struct block *block, struct symbol *sym, void *data0) return 0; } +/* Helper for add_nonlocal_symbols. Find symbols in DOMAIN which are targetted + by renamings matching NAME in BLOCK. Add these symbols to OBSTACKP. If + WILD_MATCH_P is nonzero, perform the naming matching in "wild" mode (see + function "wild_match" for more information). Return whether we found such + symbols. */ + +static int +ada_add_block_renamings (struct obstack *obstackp, + const struct block *block, + const char *name, + domain_enum domain, + int wild_match_p) +{ + struct using_direct *renaming; + int defns_mark = num_defns_collected (obstackp); + + for (renaming = block_using (block); + renaming != NULL; + renaming = renaming->next) + { + const char *r_name; + int name_match; + + /* Avoid infinite recursions: skip this renaming if we are actually + already traversing it. + + Currently, symbol lookup in Ada don't use the namespace machinery from + C++/Fortran support: skip namespace imports that use them. */ + if (renaming->searched + || (renaming->import_src != NULL + && renaming->import_src[0] != '\0') + || (renaming->import_dest != NULL + && renaming->import_dest[0] != '\0')) + continue; + renaming->searched = 1; + + /* TODO: here, we perform another name-based symbol lookup, which can + pull its own multiple overloads. In theory, we should be able to do + better in this case since, in DWARF, DW_AT_import is a DIE reference, + not a simple name. But in order to do this, we would need to enhance + the DWARF reader to associate a symbol to this renaming, instead of a + name. So, for now, we do something simpler: re-use the C++/Fortran + namespace machinery. */ + r_name = (renaming->alias != NULL + ? renaming->alias + : renaming->declaration); + name_match + = wild_match_p ? wild_match (r_name, name) : strcmp (r_name, name); + if (name_match == 0) + ada_add_all_symbols (obstackp, block, renaming->declaration, domain, + 1, NULL); + renaming->searched = 0; + } + return num_defns_collected (obstackp) != defns_mark; +} + /* Implements compare_names, but only applying the comparision using the given CASING. */ @@ -5424,6 +5484,7 @@ add_nonlocal_symbols (struct obstack *obstackp, const char *name, int is_wild_match) { struct objfile *objfile; + struct compunit_symtab *cu; struct match_data data; memset (&data, 0, sizeof data); @@ -5441,6 +5502,16 @@ add_nonlocal_symbols (struct obstack *obstackp, const char *name, objfile->sf->qf->map_matching_symbols (objfile, name, domain, global, aux_add_nonlocal_symbols, &data, full_match, compare_names); + + ALL_OBJFILE_COMPUNITS (objfile, cu) + { + const struct block *global_block + = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cu), GLOBAL_BLOCK); + + if (ada_add_block_renamings (obstackp, global_block , name, domain, + is_wild_match)) + data.found_sym = 1; + } } if (num_defns_collected (obstackp) == 0 && global && !is_wild_match) @@ -5460,43 +5531,35 @@ add_nonlocal_symbols (struct obstack *obstackp, const char *name, } } -/* Find symbols in DOMAIN matching NAME0, in BLOCK0 and, if full_search is +/* Find symbols in DOMAIN matching NAME, in BLOCK and, if FULL_SEARCH is non-zero, enclosing scope and in global scopes, returning the number of - matches. - Sets *RESULTS to point to a vector of (SYM,BLOCK) tuples, - indicating the symbols found and the blocks and symbol tables (if - any) in which they were found. This vector is transient---good only to - the next call of ada_lookup_symbol_list. + matches. Add these to OBSTACKP. - When full_search is non-zero, any non-function/non-enumeral - symbol match within the nest of blocks whose innermost member is BLOCK0, + When FULL_SEARCH is non-zero, any non-function/non-enumeral + symbol match within the nest of blocks whose innermost member is BLOCK, is the one match returned (no other matches in that or enclosing blocks is returned). If there are any matches in or - surrounding BLOCK0, then these alone are returned. + surrounding BLOCK, then these alone are returned. Names prefixed with "standard__" are handled specially: "standard__" - is first stripped off, and only static and global symbols are searched. */ + is first stripped off, and only static and global symbols are searched. -static int -ada_lookup_symbol_list_worker (const char *name0, const struct block *block0, - domain_enum domain, - struct block_symbol **results, - int full_search) + If MADE_GLOBAL_LOOKUP_P is non-null, set it before return to whether we had + to lookup global symbols. */ + +static void +ada_add_all_symbols (struct obstack *obstackp, + const struct block *block, + const char *name, + domain_enum domain, + int full_search, + int *made_global_lookup_p) { struct symbol *sym; - const struct block *block; - const char *name; - const int wild_match_p = should_use_wild_match (name0); - int syms_from_global_search = 0; - int ndefns; - - obstack_free (&symbol_list_obstack, NULL); - obstack_init (&symbol_list_obstack); - - /* Search specified block and its superiors. */ + const int wild_match_p = should_use_wild_match (name); - name = name0; - block = block0; + if (made_global_lookup_p) + *made_global_lookup_p = 0; /* Special case: If the user specifies a symbol name inside package Standard, do a non-wild matching of the symbol name without @@ -5505,10 +5568,10 @@ ada_lookup_symbol_list_worker (const char *name0, const struct block *block0, using, for instance, Standard.Constraint_Error when Constraint_Error is ambiguous (due to the user defining its own Constraint_Error entity inside its program). */ - if (startswith (name0, "standard__")) + if (startswith (name, "standard__")) { block = NULL; - name = name0 + sizeof ("standard__") - 1; + name = name + sizeof ("standard__") - 1; } /* Check the non-global symbols. If we have ANY match, then we're done. */ @@ -5516,61 +5579,88 @@ ada_lookup_symbol_list_worker (const char *name0, const struct block *block0, if (block != NULL) { if (full_search) - { - ada_add_local_symbols (&symbol_list_obstack, name, block, - domain, wild_match_p); - } + ada_add_local_symbols (obstackp, name, block, domain, wild_match_p); else { /* In the !full_search case we're are being called by ada_iterate_over_symbols, and we don't want to search superblocks. */ - ada_add_block_symbols (&symbol_list_obstack, block, name, - domain, NULL, wild_match_p); + ada_add_block_symbols (obstackp, block, name, domain, NULL, + wild_match_p); } - if (num_defns_collected (&symbol_list_obstack) > 0 || !full_search) - goto done; + if (num_defns_collected (obstackp) > 0 || !full_search) + return; } /* No non-global symbols found. Check our cache to see if we have already performed this search before. If we have, then return the same result. */ - if (lookup_cached_symbol (name0, domain, &sym, &block)) + if (lookup_cached_symbol (name, domain, &sym, &block)) { if (sym != NULL) - add_defn_to_vec (&symbol_list_obstack, sym, block); - goto done; + add_defn_to_vec (obstackp, sym, block); + return; } - syms_from_global_search = 1; + if (made_global_lookup_p) + *made_global_lookup_p = 1; /* Search symbols from all global blocks. */ - add_nonlocal_symbols (&symbol_list_obstack, name, domain, 1, - wild_match_p); + add_nonlocal_symbols (obstackp, name, domain, 1, wild_match_p); /* Now add symbols from all per-file blocks if we've gotten no hits (not strictly correct, but perhaps better than an error). */ - if (num_defns_collected (&symbol_list_obstack) == 0) - add_nonlocal_symbols (&symbol_list_obstack, name, domain, 0, - wild_match_p); + if (num_defns_collected (obstackp) == 0) + add_nonlocal_symbols (obstackp, name, domain, 0, wild_match_p); +} + +/* Find symbols in DOMAIN matching NAME, in BLOCK and, if full_search is + non-zero, enclosing scope and in global scopes, returning the number of + matches. + Sets *RESULTS to point to a vector of (SYM,BLOCK) tuples, + indicating the symbols found and the blocks and symbol tables (if + any) in which they were found. This vector is transient---good only to + the next call of ada_lookup_symbol_list. + + When full_search is non-zero, any non-function/non-enumeral + symbol match within the nest of blocks whose innermost member is BLOCK, + is the one match returned (no other matches in that or + enclosing blocks is returned). If there are any matches in or + surrounding BLOCK, then these alone are returned. + + Names prefixed with "standard__" are handled specially: "standard__" + is first stripped off, and only static and global symbols are searched. */ + +static int +ada_lookup_symbol_list_worker (const char *name, const struct block *block, + domain_enum domain, + struct block_symbol **results, + int full_search) +{ + const int wild_match_p = should_use_wild_match (name); + int syms_from_global_search; + int ndefns; + + obstack_free (&symbol_list_obstack, NULL); + obstack_init (&symbol_list_obstack); + ada_add_all_symbols (&symbol_list_obstack, block, name, domain, + full_search, &syms_from_global_search); -done: ndefns = num_defns_collected (&symbol_list_obstack); *results = defns_collected (&symbol_list_obstack, 1); ndefns = remove_extra_symbols (*results, ndefns); if (ndefns == 0 && full_search && syms_from_global_search) - cache_symbol (name0, domain, NULL, NULL); + cache_symbol (name, domain, NULL, NULL); if (ndefns == 1 && full_search && syms_from_global_search) - cache_symbol (name0, domain, (*results)[0].symbol, (*results)[0].block); - - ndefns = remove_irrelevant_renamings (*results, ndefns, block0); + cache_symbol (name, domain, (*results)[0].symbol, (*results)[0].block); + ndefns = remove_irrelevant_renamings (*results, ndefns, block); return ndefns; } @@ -6037,6 +6127,11 @@ ada_add_block_symbols (struct obstack *obstackp, } } + /* Handle renamings. */ + + if (ada_add_block_renamings (obstackp, block, name, domain, wild)) + found_sym = 1; + if (!found_sym && arg_sym != NULL) { add_defn_to_vec (obstackp, diff --git a/gdb/block.h b/gdb/block.h index d8ad3430dc7..3dbcbcbb2d7 100644 --- a/gdb/block.h +++ b/gdb/block.h @@ -82,21 +82,10 @@ struct block struct dictionary *dict; - /* Used for language-specific info. */ + /* Contains information about namespace-related info relevant to this block: + using directives and the current namespace scope. */ - union - { - struct - { - /* Contains information about namespace-related info relevant to - this block: using directives and the current namespace - scope. */ - - struct block_namespace_info *the_namespace; - } - cplus_specific; - } - language_specific; + struct block_namespace_info *namespace_info; }; /* The global block is singled out so that we can provide a back-link @@ -118,7 +107,7 @@ struct global_block #define BLOCK_FUNCTION(bl) (bl)->function #define BLOCK_SUPERBLOCK(bl) (bl)->superblock #define BLOCK_DICT(bl) (bl)->dict -#define BLOCK_NAMESPACE(bl) (bl)->language_specific.cplus_specific.the_namespace +#define BLOCK_NAMESPACE(bl) (bl)->namespace_info struct blockvector { diff --git a/gdb/buildsym.c b/gdb/buildsym.c index 2a24a25d78d..92c42d5ae68 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -503,8 +503,15 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead, opblock = pblock; } - block_set_using (block, using_directives, &objfile->objfile_obstack); - using_directives = NULL; + block_set_using (block, + (is_global + ? global_using_directives + : local_using_directives), + &objfile->objfile_obstack); + if (is_global) + global_using_directives = NULL; + else + local_using_directives = NULL; record_pending_block (objfile, block, opblock); @@ -1009,6 +1016,7 @@ prepare_for_building (const char *name, CORE_ADDR start_addr) last_source_start_addr = start_addr; local_symbols = NULL; + local_using_directives = NULL; within_function = 0; have_line_numbers = 0; @@ -1018,6 +1026,7 @@ prepare_for_building (const char *name, CORE_ADDR start_addr) a symtab, or by the really_free_pendings cleanup. */ gdb_assert (file_symbols == NULL); gdb_assert (global_symbols == NULL); + gdb_assert (global_using_directives == NULL); gdb_assert (pending_macros == NULL); gdb_assert (pending_addrmap == NULL); gdb_assert (current_subfile == NULL); @@ -1177,8 +1186,10 @@ reset_symtab_globals (void) set_last_source_file (NULL); local_symbols = NULL; + local_using_directives = NULL; file_symbols = NULL; global_symbols = NULL; + global_using_directives = NULL; /* We don't free pending_macros here because if the symtab was successfully built then ownership was transferred to the symtab. */ @@ -1281,7 +1292,8 @@ end_symtab_get_static_block (CORE_ADDR end_addr, int expandable, int required) && file_symbols == NULL && global_symbols == NULL && have_line_numbers == 0 - && pending_macros == NULL) + && pending_macros == NULL + && global_using_directives == NULL) { /* Ignore symtabs that have no functions with real debugging info. */ return NULL; @@ -1637,11 +1649,11 @@ push_context (int desc, CORE_ADDR valu) newobj->locals = local_symbols; newobj->old_blocks = pending_blocks; newobj->start_addr = valu; - newobj->using_directives = using_directives; + newobj->local_using_directives = local_using_directives; newobj->name = NULL; local_symbols = NULL; - using_directives = NULL; + local_using_directives = NULL; return newobj; } @@ -1740,7 +1752,6 @@ get_last_source_file (void) void buildsym_init (void) { - using_directives = NULL; subfile_stack = NULL; pending_addrmap_interesting = 0; @@ -1760,6 +1771,7 @@ buildsym_init (void) gdb_assert (pending_blocks == NULL); gdb_assert (file_symbols == NULL); gdb_assert (global_symbols == NULL); + gdb_assert (global_using_directives == NULL); gdb_assert (pending_macros == NULL); gdb_assert (pending_addrmap == NULL); gdb_assert (buildsym_compunit == NULL); diff --git a/gdb/buildsym.h b/gdb/buildsym.h index f98203ea521..4c0ec15a3e0 100644 --- a/gdb/buildsym.h +++ b/gdb/buildsym.h @@ -118,7 +118,11 @@ EXTERN struct pending *local_symbols; /* "using" directives local to lexical context. */ -EXTERN struct using_direct *using_directives; +EXTERN struct using_direct *local_using_directives; + +/* global "using" directives. */ + +EXTERN struct using_direct *global_using_directives; /* Stack representing unclosed lexical contexts (that will become blocks, eventually). */ @@ -131,7 +135,7 @@ struct context_stack /* Pending using directives at the time we entered. */ - struct using_direct *using_directives; + struct using_direct *local_using_directives; /* Pointer into blocklist as of entry */ diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c index f5f4bad878d..b8b19ed7af6 100644 --- a/gdb/cp-namespace.c +++ b/gdb/cp-namespace.c @@ -31,6 +31,7 @@ #include "frame.h" #include "buildsym.h" #include "language.h" +#include "namespace.h" static struct block_symbol cp_lookup_nested_symbol_1 (struct type *container_type, @@ -91,8 +92,9 @@ cp_scan_for_anonymous_namespaces (const struct symbol *const symbol, anonymous namespace. So add symbols in it to the namespace given by the previous component if there is one, or to the global namespace if there isn't. */ - cp_add_using_directive (dest, src, NULL, NULL, NULL, 1, - &objfile->objfile_obstack); + add_using_directive (&local_using_directives, + dest, src, NULL, NULL, NULL, 1, + &objfile->objfile_obstack); } /* The "+ 2" is for the "::". */ previous_component = next_component + 2; @@ -103,102 +105,6 @@ cp_scan_for_anonymous_namespaces (const struct symbol *const symbol, } } -/* Add a using directive to using_directives. If the using directive - in question has already been added, don't add it twice. - - Create a new struct using_direct which imports the namespace SRC - into the scope DEST. ALIAS is the name of the imported namespace - in the current scope. If ALIAS is NULL then the namespace is known - by its original name. DECLARATION is the name if the imported - varable if this is a declaration import (Eg. using A::x), otherwise - it is NULL. EXCLUDES is a list of names not to import from an - imported module or NULL. If COPY_NAMES is non-zero, then the - arguments are copied into newly allocated memory so they can be - temporaries. For EXCLUDES the VEC pointers are copied but the - pointed to characters are not copied. */ - -void -cp_add_using_directive (const char *dest, - const char *src, - const char *alias, - const char *declaration, - VEC (const_char_ptr) *excludes, - int copy_names, - struct obstack *obstack) -{ - struct using_direct *current; - struct using_direct *newobj; - - /* Has it already been added? */ - - for (current = using_directives; current != NULL; current = current->next) - { - int ix; - const char *param; - - if (strcmp (current->import_src, src) != 0) - continue; - if (strcmp (current->import_dest, dest) != 0) - continue; - if ((alias == NULL && current->alias != NULL) - || (alias != NULL && current->alias == NULL) - || (alias != NULL && current->alias != NULL - && strcmp (alias, current->alias) != 0)) - continue; - if ((declaration == NULL && current->declaration != NULL) - || (declaration != NULL && current->declaration == NULL) - || (declaration != NULL && current->declaration != NULL - && strcmp (declaration, current->declaration) != 0)) - continue; - - /* Compare the contents of EXCLUDES. */ - for (ix = 0; VEC_iterate (const_char_ptr, excludes, ix, param); ix++) - if (current->excludes[ix] == NULL - || strcmp (param, current->excludes[ix]) != 0) - break; - if (ix < VEC_length (const_char_ptr, excludes) - || current->excludes[ix] != NULL) - continue; - - /* Parameters exactly match CURRENT. */ - return; - } - - newobj = obstack_alloc (obstack, (sizeof (*newobj) - + (VEC_length (const_char_ptr, excludes) - * sizeof (*newobj->excludes)))); - memset (newobj, 0, sizeof (*newobj)); - - if (copy_names) - { - newobj->import_src = obstack_copy0 (obstack, src, strlen (src)); - newobj->import_dest = obstack_copy0 (obstack, dest, strlen (dest)); - } - else - { - newobj->import_src = src; - newobj->import_dest = dest; - } - - if (alias != NULL && copy_names) - newobj->alias = obstack_copy0 (obstack, alias, strlen (alias)); - else - newobj->alias = alias; - - if (declaration != NULL && copy_names) - newobj->declaration = obstack_copy0 (obstack, - declaration, strlen (declaration)); - else - newobj->declaration = declaration; - - memcpy (newobj->excludes, VEC_address (const_char_ptr, excludes), - VEC_length (const_char_ptr, excludes) * sizeof (*newobj->excludes)); - newobj->excludes[VEC_length (const_char_ptr, excludes)] = NULL; - - newobj->next = using_directives; - using_directives = newobj; -} - /* Test whether or not NAMESPACE looks like it mentions an anonymous namespace; return nonzero if so. */ diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 1625d724de0..dc0a0578d92 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -32,6 +32,7 @@ #include "expression.h" #include "value.h" #include "cp-abi.h" +#include "namespace.h" #include #include "safe-ctype.h" diff --git a/gdb/cp-support.h b/gdb/cp-support.h index f9aac3f6c63..12d8d80c6e4 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -36,6 +36,7 @@ struct block; struct objfile; struct type; struct demangle_component; +struct using_direct; /* A string representing the name of the anonymous namespace used in GDB. */ @@ -59,89 +60,6 @@ struct demangle_parse_info struct obstack obstack; }; -/* This struct is designed to store data from using directives. It - says that names from namespace IMPORT_SRC should be visible within - namespace IMPORT_DEST. These form a linked list; NEXT is the next - element of the list. If the imported namespace or declaration has - been aliased within the IMPORT_DEST namespace, ALIAS is set to a - string representing the alias. Otherwise, ALIAS is NULL. - DECLARATION is the name of the imported declaration, if this import - statement represents one. Otherwise DECLARATION is NULL and this - import statement represents a namespace. - - C++: using namespace A; - Fortran: use A - import_src = "A" - import_dest = local scope of the import statement even such as "" - alias = NULL - declaration = NULL - excludes = NULL - - C++: using A::x; - Fortran: use A, only: x - import_src = "A" - import_dest = local scope of the import statement even such as "" - alias = NULL - declaration = "x" - excludes = NULL - The declaration will get imported as import_dest::x. - - C++ has no way to import all names except those listed ones. - Fortran: use A, localname => x - import_src = "A" - import_dest = local scope of the import statement even such as "" - alias = "localname" - declaration = "x" - excludes = NULL - + - import_src = "A" - import_dest = local scope of the import statement even such as "" - alias = NULL - declaration = NULL - excludes = ["x"] - All the entries of A get imported except of "x". "x" gets imported as - "localname". "x" is not defined as a local name by this statement. - - C++: namespace LOCALNS = A; - Fortran has no way to address non-local namespace/module. - import_src = "A" - import_dest = local scope of the import statement even such as "" - alias = "LOCALNS" - declaration = NULL - excludes = NULL - The namespace will get imported as the import_dest::LOCALNS - namespace. - - C++ cannot express it, it would be something like: using localname - = A::x; - Fortran: use A, only localname => x - import_src = "A" - import_dest = local scope of the import statement even such as "" - alias = "localname" - declaration = "x" - excludes = NULL - The declaration will get imported as localname or - `import_dest`localname. */ - -struct using_direct -{ - const char *import_src; - const char *import_dest; - - const char *alias; - const char *declaration; - - struct using_direct *next; - - /* Used during import search to temporarily mark this node as - searched. */ - int searched; - - /* USING_DIRECT has variable allocation size according to the number of - EXCLUDES entries, the last entry is NULL. */ - const char *excludes[1]; -}; - /* Functions from cp-support.c. */ @@ -181,14 +99,6 @@ extern struct type *cp_lookup_rtti_type (const char *name, extern int cp_is_in_anonymous (const char *symbol_name); -extern void cp_add_using_directive (const char *dest, - const char *src, - const char *alias, - const char *declaration, - VEC (const_char_ptr) *excludes, - int copy_names, - struct obstack *obstack); - extern void cp_scan_for_anonymous_namespaces (const struct symbol *symbol, struct objfile *objfile); diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 7e7934276bd..7ae50f7a5da 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -69,6 +69,7 @@ #include "source.h" #include "filestuff.h" #include "build-id.h" +#include "namespace.h" #include #include @@ -1635,6 +1636,8 @@ static void read_namespace (struct die_info *die, struct dwarf2_cu *); static void read_module (struct die_info *die, struct dwarf2_cu *cu); +static struct using_direct **using_directives (enum language); + static void read_import_statement (struct die_info *die, struct dwarf2_cu *); static int read_namespace_alias (struct die_info *die, struct dwarf2_cu *cu); @@ -8863,6 +8866,24 @@ read_namespace_alias (struct die_info *die, struct dwarf2_cu *cu) return 0; } +/* Return the using directives repository (global or local?) to use in the + current context for LANGUAGE. + + For Ada, imported declarations can materialize renamings, which *may* be + global. However it is impossible (for now?) in DWARF to distinguish + "external" imported declarations and "static" ones. As all imported + declarations seem to be static in all other languages, make them all CU-wide + global only in Ada. */ + +static struct using_direct ** +using_directives (enum language language) +{ + if (language == language_ada && context_stack_depth == 0) + return &global_using_directives; + else + return &local_using_directives; +} + /* Read the import statement specified by the given die and record it. */ static void @@ -8999,13 +9020,14 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu) process_die (child_die, cu); } - cp_add_using_directive (import_prefix, - canonical_name, - import_alias, - imported_declaration, - excludes, - 0, - &objfile->objfile_obstack); + add_using_directive (using_directives (cu->language), + import_prefix, + canonical_name, + import_alias, + imported_declaration, + excludes, + 0, + &objfile->objfile_obstack); do_cleanups (cleanups); } @@ -11485,7 +11507,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) when we finish processing a function scope, we may need to go back to building a containing block's symbol lists. */ local_symbols = newobj->locals; - using_directives = newobj->using_directives; + local_using_directives = newobj->local_using_directives; /* If we've finished processing a top-level function, subsequent symbols go in the file symbol list. */ @@ -11531,7 +11553,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) inherit_abstract_dies (die, cu); newobj = pop_context (); - if (local_symbols != NULL || using_directives != NULL) + if (local_symbols != NULL || local_using_directives != NULL) { struct block *block = finish_block (0, &local_symbols, newobj->old_blocks, @@ -11550,7 +11572,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) dwarf2_record_block_ranges (die, block, baseaddr, cu); } local_symbols = newobj->locals; - using_directives = newobj->using_directives; + local_using_directives = newobj->local_using_directives; } /* Read in DW_TAG_GNU_call_site and insert it to CU->call_site_htab. */ @@ -14076,7 +14098,7 @@ read_namespace_type (struct die_info *die, struct dwarf2_cu *cu) return set_die_type (die, type, cu); } -/* Read a C++ namespace. */ +/* Read a namespace scope. */ static void read_namespace (struct die_info *die, struct dwarf2_cu *cu) @@ -14100,8 +14122,9 @@ read_namespace (struct die_info *die, struct dwarf2_cu *cu) { const char *previous_prefix = determine_prefix (die, cu); - cp_add_using_directive (previous_prefix, TYPE_NAME (type), NULL, - NULL, NULL, 0, &objfile->objfile_obstack); + add_using_directive (using_directives (cu->language), + previous_prefix, TYPE_NAME (type), NULL, + NULL, NULL, 0, &objfile->objfile_obstack); } } diff --git a/gdb/namespace.c b/gdb/namespace.c new file mode 100644 index 00000000000..fdbe51b580b --- /dev/null +++ b/gdb/namespace.c @@ -0,0 +1,117 @@ +/* Code dealing with "using" directives for GDB. + Copyright (C) 2003-2015 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "namespace.h" + +/* Add a using directive to USING_DIRECTIVES. If the using directive + in question has already been added, don't add it twice. + + Create a new struct using_direct which imports the namespace SRC + into the scope DEST. ALIAS is the name of the imported namespace + in the current scope. If ALIAS is NULL then the namespace is known + by its original name. DECLARATION is the name if the imported + varable if this is a declaration import (Eg. using A::x), otherwise + it is NULL. EXCLUDES is a list of names not to import from an + imported module or NULL. If COPY_NAMES is non-zero, then the + arguments are copied into newly allocated memory so they can be + temporaries. For EXCLUDES the VEC pointers are copied but the + pointed to characters are not copied. */ + +void +add_using_directive (struct using_direct **using_directives, + const char *dest, + const char *src, + const char *alias, + const char *declaration, + VEC (const_char_ptr) *excludes, + int copy_names, + struct obstack *obstack) +{ + struct using_direct *current; + struct using_direct *newobj; + + /* Has it already been added? */ + + for (current = *using_directives; current != NULL; current = current->next) + { + int ix; + const char *param; + + if (strcmp (current->import_src, src) != 0) + continue; + if (strcmp (current->import_dest, dest) != 0) + continue; + if ((alias == NULL && current->alias != NULL) + || (alias != NULL && current->alias == NULL) + || (alias != NULL && current->alias != NULL + && strcmp (alias, current->alias) != 0)) + continue; + if ((declaration == NULL && current->declaration != NULL) + || (declaration != NULL && current->declaration == NULL) + || (declaration != NULL && current->declaration != NULL + && strcmp (declaration, current->declaration) != 0)) + continue; + + /* Compare the contents of EXCLUDES. */ + for (ix = 0; VEC_iterate (const_char_ptr, excludes, ix, param); ix++) + if (current->excludes[ix] == NULL + || strcmp (param, current->excludes[ix]) != 0) + break; + if (ix < VEC_length (const_char_ptr, excludes) + || current->excludes[ix] != NULL) + continue; + + /* Parameters exactly match CURRENT. */ + return; + } + + newobj = obstack_alloc (obstack, (sizeof (*newobj) + + (VEC_length (const_char_ptr, excludes) + * sizeof (*newobj->excludes)))); + memset (newobj, 0, sizeof (*newobj)); + + if (copy_names) + { + newobj->import_src = obstack_copy0 (obstack, src, strlen (src)); + newobj->import_dest = obstack_copy0 (obstack, dest, strlen (dest)); + } + else + { + newobj->import_src = src; + newobj->import_dest = dest; + } + + if (alias != NULL && copy_names) + newobj->alias = obstack_copy0 (obstack, alias, strlen (alias)); + else + newobj->alias = alias; + + if (declaration != NULL && copy_names) + newobj->declaration = obstack_copy0 (obstack, + declaration, strlen (declaration)); + else + newobj->declaration = declaration; + + memcpy (newobj->excludes, VEC_address (const_char_ptr, excludes), + VEC_length (const_char_ptr, excludes) * sizeof (*newobj->excludes)); + newobj->excludes[VEC_length (const_char_ptr, excludes)] = NULL; + + newobj->next = *using_directives; + *using_directives = newobj; +} diff --git a/gdb/namespace.h b/gdb/namespace.h new file mode 100644 index 00000000000..aa73f4a7ec1 --- /dev/null +++ b/gdb/namespace.h @@ -0,0 +1,118 @@ +/* Code dealing with "using" directives for GDB. + Copyright (C) 2003-2015 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef NAMESPACE_H +#define NAMESPACE_H + +#include "vec.h" +#include "gdb_vecs.h" +#include "gdb_obstack.h" + +/* This struct is designed to store data from using directives. It + says that names from namespace IMPORT_SRC should be visible within + namespace IMPORT_DEST. These form a linked list; NEXT is the next + element of the list. If the imported namespace or declaration has + been aliased within the IMPORT_DEST namespace, ALIAS is set to a + string representing the alias. Otherwise, ALIAS is NULL. + DECLARATION is the name of the imported declaration, if this import + statement represents one. Otherwise DECLARATION is NULL and this + import statement represents a namespace. + + C++: using namespace A; + Fortran: use A + import_src = "A" + import_dest = local scope of the import statement even such as "" + alias = NULL + declaration = NULL + excludes = NULL + + C++: using A::x; + Fortran: use A, only: x + import_src = "A" + import_dest = local scope of the import statement even such as "" + alias = NULL + declaration = "x" + excludes = NULL + The declaration will get imported as import_dest::x. + + C++ has no way to import all names except those listed ones. + Fortran: use A, localname => x + import_src = "A" + import_dest = local scope of the import statement even such as "" + alias = "localname" + declaration = "x" + excludes = NULL + + + import_src = "A" + import_dest = local scope of the import statement even such as "" + alias = NULL + declaration = NULL + excludes = ["x"] + All the entries of A get imported except of "x". "x" gets imported as + "localname". "x" is not defined as a local name by this statement. + + C++: namespace LOCALNS = A; + Fortran has no way to address non-local namespace/module. + import_src = "A" + import_dest = local scope of the import statement even such as "" + alias = "LOCALNS" + declaration = NULL + excludes = NULL + The namespace will get imported as the import_dest::LOCALNS + namespace. + + C++ cannot express it, it would be something like: using localname + = A::x; + Fortran: use A, only localname => x + import_src = "A" + import_dest = local scope of the import statement even such as "" + alias = "localname" + declaration = "x" + excludes = NULL + The declaration will get imported as localname or + `import_dest`localname. */ + +struct using_direct +{ + const char *import_src; + const char *import_dest; + + const char *alias; + const char *declaration; + + struct using_direct *next; + + /* Used during import search to temporarily mark this node as + searched. */ + int searched; + + /* USING_DIRECT has variable allocation size according to the number of + EXCLUDES entries, the last entry is NULL. */ + const char *excludes[1]; +}; + +extern void add_using_directive (struct using_direct **using_directives, + const char *dest, + const char *src, + const char *alias, + const char *declaration, + VEC (const_char_ptr) *excludes, + int copy_names, + struct obstack *obstack); + +#endif /* NAMESPACE_H */ diff --git a/gdb/testsuite/gdb.ada/fun_renaming.exp b/gdb/testsuite/gdb.ada/fun_renaming.exp new file mode 100644 index 00000000000..fa7617139ed --- /dev/null +++ b/gdb/testsuite/gdb.ada/fun_renaming.exp @@ -0,0 +1,83 @@ +# Copyright 2015 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +load_lib "ada.exp" + +standard_ada_testfile fun_renaming + +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug]] != "" } { + return -1 +} + +clean_restart ${testfile} + +set bp_location [gdb_get_line_number "BREAK" ${testdir}/fun_renaming.adb] +runto "fun_renaming.adb:$bp_location" + +# Sanity check: make sure we can call a regular global function. +gdb_test "print next(1)" " = 2" + +# Starting with GCC 6, renamed subprograms are materialized in the debugging +# information: make sure we can call the regular global function using its +# multiple names. + +set test "print n(1)" +gdb_test_multiple $test $test { + -re " = 2\..*$gdb_prompt $" { + pass $test + } + -re "No definition of \"n\" in current context\..*$gdb_prompt $" { + if {[test_compiler_info {gcc-6*}]} { + fail $test + } else { + xfail $test + } + } + +} +set test "print renamed_next(1)" +gdb_test_multiple $test $test { + -re " = 2\..*$gdb_prompt $" { + pass $test + } + -re "No definition of \"renamed_next\" in current context\..*$gdb_prompt $" { + if {[test_compiler_info {gcc-6*}]} { + fail $test + } else { + xfail $test + } + } +} + +set test "print pack.renamed_next(1)" +gdb_test_multiple $test $test { + -re " = 2\..*$gdb_prompt $" { + pass $test + } + -re "No definition of \"pack\.renamed_next\" in current context\..*$gdb_prompt $" { + if {[test_compiler_info {gcc-6*}]} { + fail $test + } else { + xfail $test + } + } + -re "Type is not a structure or union type\..*$gdb_prompt $" { + if {[test_compiler_info {gcc-6*}]} { + fail $test + } else { + xfail $test + } + } +} diff --git a/gdb/testsuite/gdb.ada/fun_renaming/fun_renaming.adb b/gdb/testsuite/gdb.ada/fun_renaming/fun_renaming.adb new file mode 100644 index 00000000000..c9335858634 --- /dev/null +++ b/gdb/testsuite/gdb.ada/fun_renaming/fun_renaming.adb @@ -0,0 +1,23 @@ +-- Copyright 2015 Free Software Foundation, Inc. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +with Pack; + +procedure Fun_Renaming is + function N (I : Integer) return Integer renames Pack.Next; +begin + Pack.Discard (N (1)); -- BREAK + Pack.Discard (Pack.Renamed_Next (1)); -- BREAK +end Fun_Renaming; diff --git a/gdb/testsuite/gdb.ada/fun_renaming/pack.adb b/gdb/testsuite/gdb.ada/fun_renaming/pack.adb new file mode 100644 index 00000000000..bdcd4320887 --- /dev/null +++ b/gdb/testsuite/gdb.ada/fun_renaming/pack.adb @@ -0,0 +1,26 @@ +-- Copyright 2015 Free Software Foundation, Inc. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +package body Pack is + function Next (I : Integer) return Integer is + begin + return I + 1; + end Next; + + procedure Discard (I : Integer) is + begin + null; + end Discard; +end Pack; diff --git a/gdb/testsuite/gdb.ada/fun_renaming/pack.ads b/gdb/testsuite/gdb.ada/fun_renaming/pack.ads new file mode 100644 index 00000000000..2cf722cfebe --- /dev/null +++ b/gdb/testsuite/gdb.ada/fun_renaming/pack.ads @@ -0,0 +1,22 @@ +-- Copyright 2015 Free Software Foundation, Inc. +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +package Pack is + + function Next (I : Integer) return Integer; + function Renamed_Next (I : Integer) return Integer renames Next; + procedure Discard (I : Integer); + +end Pack;