/* Helper routines for C++ support in GDB.
- Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 2003-2014 Free Software Foundation, Inc.
Contributed by David Carlton and by Kealia, Inc.
#include "gdb_obstack.h"
#include "symtab.h"
#include "symfile.h"
-#include "gdb_assert.h"
#include "block.h"
#include "objfiles.h"
#include "gdbtypes.h"
static struct symbol *lookup_symbol_file (const char *name,
const struct block *block,
const domain_enum domain,
- int anonymous_namespace);
+ int anonymous_namespace,
+ int search);
static struct type *cp_lookup_transparent_type_loop (const char *name,
const char *scope,
/* Check to see if SYMBOL refers to an object contained within an
anonymous namespace; if so, add an appropriate using directive. */
-/* Optimize away strlen ("(anonymous namespace)"). */
-
-#define ANONYMOUS_NAMESPACE_LEN 21
-
void
-cp_scan_for_anonymous_namespaces (const struct symbol *symbol)
+cp_scan_for_anonymous_namespaces (const struct symbol *const symbol,
+ struct objfile *const objfile)
{
if (SYMBOL_DEMANGLED_NAME (symbol) != NULL)
{
while (name[next_component] == ':')
{
- if ((next_component - previous_component) == ANONYMOUS_NAMESPACE_LEN
+ if (((next_component - previous_component)
+ == CP_ANONYMOUS_NAMESPACE_LEN)
&& strncmp (name + previous_component,
- "(anonymous namespace)",
- ANONYMOUS_NAMESPACE_LEN) == 0)
+ CP_ANONYMOUS_NAMESPACE_STR,
+ CP_ANONYMOUS_NAMESPACE_LEN) == 0)
{
int dest_len = (previous_component == 0
? 0 : previous_component - 2);
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,
- &SYMBOL_SYMTAB (symbol)->objfile->objfile_obstack);
+ cp_add_using_directive (dest, src, NULL, NULL, NULL, 1,
+ &objfile->objfile_obstack);
}
/* The "+ 2" is for the "::". */
previous_component = next_component + 2;
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. The arguments are copied into newly allocated memory
- so they can be temporaries. */
+ 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;
for (current = using_directives; current != NULL; current = current->next)
{
- if (strcmp (current->import_src, src) == 0
- && strcmp (current->import_dest, dest) == 0
- && ((alias == NULL && current->alias == NULL)
- || (alias != NULL && current->alias != NULL
- && strcmp (alias, current->alias) == 0))
- && ((declaration == NULL && current->declaration == NULL)
- || (declaration != NULL && current->declaration != NULL
- && strcmp (declaration, current->declaration) == 0)))
- return;
+ 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;
}
- new = OBSTACK_ZALLOC (obstack, struct using_direct);
-
- new->import_src = obsavestring (src, strlen (src), obstack);
- new->import_dest = obsavestring (dest, strlen (dest), obstack);
-
- if (alias != NULL)
- new->alias = obsavestring (alias, strlen (alias), obstack);
-
- if (declaration != NULL)
- new->declaration = obsavestring (declaration, strlen (declaration),
- obstack);
-
- new->next = using_directives;
- using_directives = new;
-}
-
-/* Record the namespace that the function defined by SYMBOL was
- defined in, if necessary. BLOCK is the associated block; use
- OBSTACK for allocation. */
+ new = obstack_alloc (obstack, (sizeof (*new)
+ + (VEC_length (const_char_ptr, excludes)
+ * sizeof (*new->excludes))));
+ memset (new, 0, sizeof (*new));
-void
-cp_set_block_scope (const struct symbol *symbol,
- struct block *block,
- struct obstack *obstack,
- const char *processing_current_prefix,
- int processing_has_namespace_info)
-{
- if (processing_has_namespace_info)
+ if (copy_names)
{
- block_set_scope
- (block, obsavestring (processing_current_prefix,
- strlen (processing_current_prefix),
- obstack),
- obstack);
+ new->import_src = obstack_copy0 (obstack, src, strlen (src));
+ new->import_dest = obstack_copy0 (obstack, dest, strlen (dest));
}
- else if (SYMBOL_DEMANGLED_NAME (symbol) != NULL)
+ else
{
- /* Try to figure out the appropriate namespace from the
- demangled name. */
+ new->import_src = src;
+ new->import_dest = dest;
+ }
- /* FIXME: carlton/2003-04-15: If the function in question is
- a method of a class, the name will actually include the
- name of the class as well. This should be harmless, but
- is a little unfortunate. */
+ if (alias != NULL && copy_names)
+ new->alias = obstack_copy0 (obstack, alias, strlen (alias));
+ else
+ new->alias = alias;
- const char *name = SYMBOL_DEMANGLED_NAME (symbol);
- unsigned int prefix_len = cp_entire_prefix_len (name);
+ if (declaration != NULL && copy_names)
+ new->declaration = obstack_copy0 (obstack,
+ declaration, strlen (declaration));
+ else
+ new->declaration = declaration;
- block_set_scope (block,
- obsavestring (name, prefix_len, obstack),
- obstack);
- }
+ memcpy (new->excludes, VEC_address (const_char_ptr, excludes),
+ VEC_length (const_char_ptr, excludes) * sizeof (*new->excludes));
+ new->excludes[VEC_length (const_char_ptr, excludes)] = NULL;
+
+ new->next = using_directives;
+ using_directives = new;
}
/* Test whether or not NAMESPACE looks like it mentions an anonymous
int
cp_is_anonymous (const char *namespace)
{
- return (strstr (namespace, "(anonymous namespace)")
+ return (strstr (namespace, CP_ANONYMOUS_NAMESPACE_STR)
!= NULL);
}
}
/* Look up NAME in the C++ namespace NAMESPACE. Other arguments are
- as in cp_lookup_symbol_nonlocal. */
+ as in cp_lookup_symbol_nonlocal. If SEARCH is non-zero, search
+ through base classes for a matching symbol. */
static struct symbol *
cp_lookup_symbol_in_namespace (const char *namespace,
const char *name,
const struct block *block,
- const domain_enum domain)
+ const domain_enum domain, int search)
{
if (namespace[0] == '\0')
{
- return lookup_symbol_file (name, block, domain, 0);
+ return lookup_symbol_file (name, block, domain, 0, search);
}
else
{
strcat (concatenated_name, "::");
strcat (concatenated_name, name);
return lookup_symbol_file (concatenated_name, block, domain,
- cp_is_anonymous (namespace));
+ cp_is_anonymous (namespace), search);
}
}
/* First, try to find the symbol in the given namespace. */
if (!declaration_only)
sym = cp_lookup_symbol_in_namespace (scope, name,
- block, domain);
+ block, domain, 1);
if (sym != NULL)
return sym;
current != NULL;
current = current->next)
{
+ const char **excludep;
+
len = strlen (current->import_dest);
directive_match = (search_parents
? (strncmp (scope, current->import_dest,
ancestors then it is applicable. */
if (directive_match && !current->searched)
{
- /* Mark this import as searched so that the recursive call
- does not search it again. */
- current->searched = 1;
- searched_cleanup = make_cleanup (reset_directive_searched,
- current);
-
- /* If there is an import of a single declaration, compare the
- imported declaration (after optional renaming by its alias)
- with the sought out name. If there is a match pass
- current->import_src as NAMESPACE to direct the search
- towards the imported namespace. */
- if (current->declaration
- && strcmp (name, current->alias
- ? current->alias : current->declaration) == 0)
- sym = cp_lookup_symbol_in_namespace (current->import_src,
- current->declaration,
- block, domain);
-
- /* If this is a DECLARATION_ONLY search or a symbol was found
- or this import statement was an import declaration, the
- search of this import is complete. */
- if (declaration_only || sym != NULL || current->declaration)
- {
- current->searched = 0;
- discard_cleanups (searched_cleanup);
-
- if (sym != NULL)
- return sym;
-
- continue;
- }
-
- if (current->alias != NULL
- && strcmp (name, current->alias) == 0)
- /* If the import is creating an alias and the alias matches
- the sought name. Pass current->import_src as the NAME to
- direct the search towards the aliased namespace. */
- {
- sym = cp_lookup_symbol_in_namespace (scope,
- current->import_src,
- block, domain);
- }
- else if (current->alias == NULL)
- {
- /* If this import statement creates no alias, pass
- current->inner as NAMESPACE to direct the search
- towards the imported namespace. */
- sym = cp_lookup_symbol_imports (current->import_src,
- name, block,
- domain, 0, 0);
- }
- current->searched = 0;
- discard_cleanups (searched_cleanup);
+ /* Mark this import as searched so that the recursive call
+ does not search it again. */
+ current->searched = 1;
+ searched_cleanup = make_cleanup (reset_directive_searched,
+ current);
+
+ /* If there is an import of a single declaration, compare the
+ imported declaration (after optional renaming by its alias)
+ with the sought out name. If there is a match pass
+ current->import_src as NAMESPACE to direct the search
+ towards the imported namespace. */
+ if (current->declaration
+ && strcmp (name, current->alias
+ ? current->alias : current->declaration) == 0)
+ sym = cp_lookup_symbol_in_namespace (current->import_src,
+ current->declaration,
+ block, domain, 1);
+
+ /* If this is a DECLARATION_ONLY search or a symbol was found
+ or this import statement was an import declaration, the
+ search of this import is complete. */
+ if (declaration_only || sym != NULL || current->declaration)
+ {
+ current->searched = 0;
+ discard_cleanups (searched_cleanup);
- if (sym != NULL)
- return sym;
+ if (sym != NULL)
+ return sym;
+
+ continue;
+ }
+
+ /* Do not follow CURRENT if NAME matches its EXCLUDES. */
+ for (excludep = current->excludes; *excludep; excludep++)
+ if (strcmp (name, *excludep) == 0)
+ break;
+ if (*excludep)
+ {
+ discard_cleanups (searched_cleanup);
+ continue;
+ }
+
+ if (current->alias != NULL
+ && strcmp (name, current->alias) == 0)
+ /* If the import is creating an alias and the alias matches
+ the sought name. Pass current->import_src as the NAME to
+ direct the search towards the aliased namespace. */
+ {
+ sym = cp_lookup_symbol_in_namespace (scope,
+ current->import_src,
+ block, domain, 1);
+ }
+ else if (current->alias == NULL)
+ {
+ /* If this import statement creates no alias, pass
+ current->inner as NAMESPACE to direct the search
+ towards the imported namespace. */
+ sym = cp_lookup_symbol_imports (current->import_src,
+ name, block,
+ domain, 0, 0);
+ }
+ current->searched = 0;
+ discard_cleanups (searched_cleanup);
+
+ if (sym != NULL)
+ return sym;
}
}
if (function != NULL && SYMBOL_LANGUAGE (function) == language_cplus)
{
- int i;
- struct cplus_specific *cps
- = function->ginfo.language_specific.cplus_specific;
-
/* Search the function's template parameters. */
if (SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (function))
{
char *name_copy = xstrdup (SYMBOL_NATURAL_NAME (function));
struct cleanup *cleanups = make_cleanup (xfree, name_copy);
const struct language_defn *lang = language_def (language_cplus);
- struct gdbarch *arch = SYMBOL_SYMTAB (function)->objfile->gdbarch;
+ struct gdbarch *arch
+ = get_objfile_arch (SYMBOL_SYMTAB (function)->objfile);
const struct block *parent = BLOCK_SUPERBLOCK (block);
while (1)
TYPE_N_TEMPLATE_ARGUMENTS (context),
TYPE_TEMPLATE_ARGUMENTS (context));
if (result != NULL)
- return result;
+ {
+ do_cleanups (cleanups);
+ return result;
+ }
}
do_cleanups (cleanups);
/* First, try to find the symbol in the given namespace. */
sym = cp_lookup_symbol_in_namespace (scope, name,
- block, domain);
+ block, domain, 1);
if (sym != NULL)
return sym;
strncpy (namespace, scope, scope_len);
namespace[scope_len] = '\0';
return cp_lookup_symbol_in_namespace (namespace, name,
- block, domain);
+ block, domain, 1);
}
/* Look up NAME in BLOCK's static block and in global blocks. If
ANONYMOUS_NAMESPACE is nonzero, the symbol in question is located
- within an anonymous namespace. Other arguments are as in
+ within an anonymous namespace. If SEARCH is non-zero, search through
+ base classes for a matching symbol. Other arguments are as in
cp_lookup_symbol_nonlocal. */
static struct symbol *
lookup_symbol_file (const char *name,
const struct block *block,
const domain_enum domain,
- int anonymous_namespace)
+ int anonymous_namespace, int search)
{
struct symbol *sym = NULL;
sym = lookup_symbol_global (name, block, domain);
}
+ if (sym != NULL)
+ return sym;
+
+ if (search)
+ {
+ char *klass, *nested;
+ unsigned int prefix_len;
+ struct cleanup *cleanup;
+ struct symbol *klass_sym;
+
+ /* A simple lookup failed. Check if the symbol was defined in
+ a base class. */
+
+ cleanup = make_cleanup (null_cleanup, NULL);
+
+ /* Find the name of the class and the name of the method,
+ variable, etc. */
+ prefix_len = cp_entire_prefix_len (name);
+
+ /* If no prefix was found, search "this". */
+ if (prefix_len == 0)
+ {
+ struct type *type;
+ struct symbol *this;
+
+ this = lookup_language_this (language_def (language_cplus), block);
+ if (this == NULL)
+ {
+ do_cleanups (cleanup);
+ return NULL;
+ }
+
+ type = check_typedef (TYPE_TARGET_TYPE (SYMBOL_TYPE (this)));
+ /* If TYPE_NAME is NULL, abandon trying to find this symbol.
+ This can happen for lambda functions compiled with clang++,
+ which outputs no name for the container class. */
+ if (TYPE_NAME (type) == NULL)
+ return NULL;
+ klass = xstrdup (TYPE_NAME (type));
+ nested = xstrdup (name);
+ }
+ else
+ {
+ /* The class name is everything up to and including PREFIX_LEN. */
+ klass = savestring (name, prefix_len);
+
+ /* The rest of the name is everything else past the initial scope
+ operator. */
+ nested = xstrdup (name + prefix_len + 2);
+ }
+
+ /* Add cleanups to free memory for these strings. */
+ make_cleanup (xfree, klass);
+ make_cleanup (xfree, nested);
+
+ /* Lookup a class named KLASS. If none is found, there is nothing
+ more that can be done. */
+ klass_sym = lookup_symbol_global (klass, block, domain);
+ if (klass_sym == NULL)
+ {
+ do_cleanups (cleanup);
+ return NULL;
+ }
+
+ /* Look for a symbol named NESTED in this class. */
+ sym = cp_lookup_nested_symbol (SYMBOL_TYPE (klass_sym), nested, block);
+ do_cleanups (cleanup);
+ }
+
+ return sym;
+}
+
+/* Search through the base classes of PARENT_TYPE for a base class
+ named NAME and return its type. If not found, return NULL. */
+
+struct type *
+find_type_baseclass_by_name (struct type *parent_type, const char *name)
+{
+ int i;
+
+ CHECK_TYPEDEF (parent_type);
+ for (i = 0; i < TYPE_N_BASECLASSES (parent_type); ++i)
+ {
+ struct type *type = check_typedef (TYPE_BASECLASS (parent_type, i));
+ const char *base_name = TYPE_BASECLASS_NAME (parent_type, i);
+
+ if (base_name == NULL)
+ continue;
+
+ if (streq (base_name, name))
+ return type;
+
+ type = find_type_baseclass_by_name (type, name);
+ if (type != NULL)
+ return type;
+ }
+
+ return NULL;
+}
+
+/* Search through the base classes of PARENT_TYPE for a symbol named
+ NAME in block BLOCK. */
+
+static struct symbol *
+find_symbol_in_baseclass (struct type *parent_type, const char *name,
+ const struct block *block)
+{
+ int i;
+ struct symbol *sym;
+ struct cleanup *cleanup;
+ char *concatenated_name;
+
+ sym = NULL;
+ concatenated_name = NULL;
+ cleanup = make_cleanup (free_current_contents, &concatenated_name);
+ for (i = 0; i < TYPE_N_BASECLASSES (parent_type); ++i)
+ {
+ size_t len;
+ struct type *base_type = TYPE_BASECLASS (parent_type, i);
+ const char *base_name = TYPE_BASECLASS_NAME (parent_type, i);
+
+ if (base_name == NULL)
+ continue;
+
+ /* Search this particular base class. */
+ sym = cp_lookup_symbol_in_namespace (base_name, name, block,
+ VAR_DOMAIN, 0);
+ if (sym != NULL)
+ break;
+
+ /* Now search all static file-level symbols. We have to do this for
+ things like typedefs in the class. First search in this symtab,
+ what we want is possibly there. */
+ len = strlen (base_name) + 2 + strlen (name) + 1;
+ concatenated_name = xrealloc (concatenated_name, len);
+ xsnprintf (concatenated_name, len, "%s::%s", base_name, name);
+ sym = lookup_symbol_static (concatenated_name, block, VAR_DOMAIN);
+ if (sym != NULL)
+ break;
+
+ /* Nope. We now have to search all static blocks in all objfiles,
+ even if block != NULL, because there's no guarantees as to which
+ symtab the symbol we want is in. */
+ sym = lookup_static_symbol_aux (concatenated_name, VAR_DOMAIN);
+ if (sym != NULL)
+ break;
+
+ /* If this class has base classes, search them next. */
+ CHECK_TYPEDEF (base_type);
+ if (TYPE_N_BASECLASSES (base_type) > 0)
+ {
+ sym = find_symbol_in_baseclass (base_type, name, block);
+ if (sym != NULL)
+ break;
+ }
+ }
+
+ do_cleanups (cleanup);
return sym;
}
-/* Look up a type named NESTED_NAME that is nested inside the C++
+/* Look up a symbol named NESTED_NAME that is nested inside the C++
class or namespace given by PARENT_TYPE, from within the context
given by BLOCK. Return NULL if there is no such nested type. */
-struct type *
-cp_lookup_nested_type (struct type *parent_type,
- const char *nested_name,
- const struct block *block)
+struct symbol *
+cp_lookup_nested_symbol (struct type *parent_type,
+ const char *nested_name,
+ const struct block *block)
{
/* type_name_no_tag_required provides better error reporting using the
original type. */
case TYPE_CODE_STRUCT:
case TYPE_CODE_NAMESPACE:
case TYPE_CODE_UNION:
+ case TYPE_CODE_ENUM:
+ /* NOTE: Handle modules here as well, because Fortran is re-using the C++
+ specific code to lookup nested symbols in modules, by calling the
+ function pointer la_lookup_symbol_nonlocal, which ends up here. */
+ case TYPE_CODE_MODULE:
{
/* NOTE: carlton/2003-11-10: We don't treat C++ class members
of classes like, say, data or function members. Instead,
just like members of namespaces; in particular,
lookup_symbol_namespace works when looking them up. */
+ int size;
const char *parent_name = type_name_no_tag_or_error (saved_parent_type);
struct symbol *sym
= cp_lookup_symbol_in_namespace (parent_name, nested_name,
- block, VAR_DOMAIN);
+ block, VAR_DOMAIN, 0);
char *concatenated_name;
- if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
- return SYMBOL_TYPE (sym);
+ if (sym != NULL)
+ return sym;
- /* Now search all static file-level symbols. Not strictly
- correct, but more useful than an error. We do not try to
+ /* Now search all static file-level symbols. We have to do this
+ for things like typedefs in the class. We do not try to
guess any imported namespace as even the fully specified
- namespace seach is is already not C++ compliant and more
+ namespace search is already not C++ compliant and more
assumptions could make it too magic. */
- concatenated_name = alloca (strlen (parent_name) + 2
- + strlen (nested_name) + 1);
- sprintf (concatenated_name, "%s::%s",
+ size = strlen (parent_name) + 2 + strlen (nested_name) + 1;
+ concatenated_name = alloca (size);
+ xsnprintf (concatenated_name, size, "%s::%s",
parent_name, nested_name);
- sym = lookup_static_symbol_aux (concatenated_name,
- VAR_DOMAIN);
- if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
- return SYMBOL_TYPE (sym);
+ sym = lookup_static_symbol_aux (concatenated_name, VAR_DOMAIN);
+ if (sym != NULL)
+ return sym;
- return NULL;
+ /* If no matching symbols were found, try searching any
+ base classes. */
+ return find_symbol_in_baseclass (parent_type, nested_name, block);
}
+
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_METHOD:
+ return NULL;
+
default:
internal_error (__FILE__, __LINE__,
- _("cp_lookup_nested_type called "
+ _("cp_lookup_nested_symbol called "
"on a non-aggregate type."));
}
}