[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
<https://gcc.gnu.org/ml/gcc-patches/2015-07/msg02166.html>.
This commit is contained in:
Pierre-Marie de Rodat 2015-07-22 15:30:57 +02:00
parent 19c2883a9b
commit 22cee43f9a
15 changed files with 608 additions and 278 deletions

View File

@ -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 \

View File

@ -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;
const int wild_match_p = should_use_wild_match (name);
obstack_free (&symbol_list_obstack, NULL);
obstack_init (&symbol_list_obstack);
/* Search specified block and its superiors. */
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,

View File

@ -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
{

View File

@ -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);

View File

@ -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 */

View File

@ -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. */

View File

@ -32,6 +32,7 @@
#include "expression.h"
#include "value.h"
#include "cp-abi.h"
#include "namespace.h"
#include <signal.h>
#include "safe-ctype.h"

View File

@ -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);

View File

@ -69,6 +69,7 @@
#include "source.h"
#include "filestuff.h"
#include "build-id.h"
#include "namespace.h"
#include <fcntl.h>
#include <sys/types.h>
@ -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);
}
}

117
gdb/namespace.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>. */
#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;
}

118
gdb/namespace.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>. */
#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 */

View File

@ -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 <http://www.gnu.org/licenses/>.
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 <data variable, no debug info> is not a structure or union type\..*$gdb_prompt $" {
if {[test_compiler_info {gcc-6*}]} {
fail $test
} else {
xfail $test
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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;

View File

@ -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 <http://www.gnu.org/licenses/>.
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;

View File

@ -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 <http://www.gnu.org/licenses/>.
package Pack is
function Next (I : Integer) return Integer;
function Renamed_Next (I : Integer) return Integer renames Next;
procedure Discard (I : Integer);
end Pack;