PR c++/13615

* cp-namespace.c (cp_lookup_symbol_in_namespace): Add SEARCH
	parameter and pass it to lookup_symbol_file.
	(cp_lookup_symbol_imports): Tell cp_lookup_symbol_in_namespace
	to search base classes.
	(cp_lookup_symbol_namespace): Likewise.
	(lookup_namespace_scope): Likewise.
	(lookup_symbol_file): Add SEARCH parameter.
	If SEARCH is non-zero and no symbol is found, lookup the class
	and call cp_lookup_nested_symbol.
	(find_symbol_in_baseclass): New function.
	(cp_lookup_nested_symbol): Do not let
	cp_lookup_symbol_in_namespace search through base classes.
	Do that later when there is no global symbol match.

	PR c++/13615
	* gdb.cp/baseenum.cc: New file.
	* gdb.cp/baseenum.exp: New file.
	* gdb.cp/derivation.cc (A): Add copyright.
	Add a typedef.
	(B): Use A::value_type instead of int.  Change all references.
	(D): Use value_type instead of int.  Change all references.
	(E): Likewise.
	(F); Likewise.
	(Z): New class.
	(ZZ): New class.
 	(N, Base, Derived): New namespace and classes.
	(main): Add instances of Z and ZZ.
	Make sure all symbols from N are kept.
	* gdb.cp/derivation.exp: Update typedef changes in tests.
	Add tests for class typedefs both before and after starting
	the inferior.
	Add tests for searching for a typedef while stopped in a
	method.
This commit is contained in:
Keith Seitz 2012-11-16 20:54:30 +00:00
parent e64e03922c
commit 8dea366bbe
7 changed files with 456 additions and 68 deletions

View File

@ -1,3 +1,20 @@
2012-11-16 Keith Seitz <keiths@redhat.com>
PR c++/13615
* cp-namespace.c (cp_lookup_symbol_in_namespace): Add SEARCH
parameter and pass it to lookup_symbol_file.
(cp_lookup_symbol_imports): Tell cp_lookup_symbol_in_namespace
to search base classes.
(cp_lookup_symbol_namespace): Likewise.
(lookup_namespace_scope): Likewise.
(lookup_symbol_file): Add SEARCH parameter.
If SEARCH is non-zero and no symbol is found, lookup the class
and call cp_lookup_nested_symbol.
(find_symbol_in_baseclass): New function.
(cp_lookup_nested_symbol): Do not let
cp_lookup_symbol_in_namespace search through base classes.
Do that later when there is no global symbol match.
2012-11-16 Doug Evans <dje@google.com>
* main.c (gdb_datadir_provided): New static global.

View File

@ -42,7 +42,8 @@ static struct symbol *lookup_namespace_scope (const char *name,
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,
@ -264,17 +265,18 @@ cp_lookup_symbol_nonlocal (const char *name,
}
/* 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
{
@ -285,7 +287,7 @@ cp_lookup_symbol_in_namespace (const char *namespace,
strcat (concatenated_name, "::");
strcat (concatenated_name, name);
return lookup_symbol_file (concatenated_name, block, domain,
cp_is_anonymous (namespace));
cp_is_anonymous (namespace), search);
}
}
@ -341,7 +343,7 @@ cp_lookup_symbol_imports (const char *scope,
/* 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;
@ -385,7 +387,7 @@ cp_lookup_symbol_imports (const char *scope,
? current->alias : current->declaration) == 0)
sym = cp_lookup_symbol_in_namespace (current->import_src,
current->declaration,
block, domain);
block, domain, 1);
/* If this is a DECLARATION_ONLY search or a symbol was found
or this import statement was an import declaration, the
@ -419,7 +421,7 @@ cp_lookup_symbol_imports (const char *scope,
{
sym = cp_lookup_symbol_in_namespace (scope,
current->import_src,
block, domain);
block, domain, 1);
}
else if (current->alias == NULL)
{
@ -550,7 +552,7 @@ cp_lookup_symbol_namespace (const char *scope,
/* 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;
@ -621,19 +623,20 @@ lookup_namespace_scope (const char *name,
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;
@ -657,6 +660,127 @@ lookup_symbol_file (const char *name,
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)));
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 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;
const char *base_name = TYPE_BASECLASS_NAME (parent_type, i);
if (base_name == NULL)
continue;
/* Search this particular base class. */
sym = cp_lookup_symbol_namespace (base_name, name, block, VAR_DOMAIN);
if (sym != NULL)
break;
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 there is currently no BLOCK, e.g., the inferior hasn't yet
been started, then try searching all STATIC_BLOCK symbols in
all objfiles. */
if (block == NULL)
{
sym = lookup_static_symbol_aux (concatenated_name, VAR_DOMAIN);
if (sym != NULL)
break;
}
/* If this class has base classes, search them next. */
if (TYPE_N_BASECLASSES (TYPE_BASECLASS (parent_type, i)) > 0)
{
sym = find_symbol_in_baseclass (TYPE_BASECLASS (parent_type, i),
name, block);
if (sym != NULL)
break;
}
}
do_cleanups (cleanup);
return sym;
}
@ -692,7 +816,7 @@ cp_lookup_nested_symbol (struct type *parent_type,
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)
@ -701,7 +825,7 @@ cp_lookup_nested_symbol (struct type *parent_type,
/* Now search all static file-level symbols. Not strictly
correct, but more useful than an error. 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. */
size = strlen (parent_name) + 2 + strlen (nested_name) + 1;
@ -712,7 +836,9 @@ cp_lookup_nested_symbol (struct type *parent_type,
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);
}
default:
internal_error (__FILE__, __LINE__,

View File

@ -1,3 +1,25 @@
2012-11-16 Keith Seitz <keiths@redhat.com>
PR c++/13615
* gdb.cp/baseenum.cc: New file.
* gdb.cp/baseenum.exp: New file.
* gdb.cp/derivation.cc (A): Add copyright.
Add a typedef.
(B): Use A::value_type instead of int. Change all references.
(D): Use value_type instead of int. Change all references.
(E): Likewise.
(F); Likewise.
(Z): New class.
(ZZ): New class.
(N, Base, Derived): New namespace and classes.
(main): Add instances of Z and ZZ.
Make sure all symbols from N are kept.
* gdb.cp/derivation.exp: Update typedef changes in tests.
Add tests for class typedefs both before and after starting
the inferior.
Add tests for searching for a typedef while stopped in a
method.
2012-11-14 Luis Machado <lgustavo@codesourcery.com>
* gdb.mi/mi-var-create-rtti.c: New file.

View File

@ -0,0 +1,81 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2003-2004, 2007-2012 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/>.
*/
class A
{
public:
enum E {X,Y,Z};
};
class B1 : public A
{
};
class B2 : public A
{
};
class C : public B1, public B2
{
public:
void test(E e);
};
void C::test(E e)
{
if (e == X) // breakpoint 1
{
}
}
namespace N
{
class A
{
public:
enum E {X, Y, Z};
};
class B1 {};
class B2 : public A {};
class C : public B1, public B2
{
public:
void test (E e);
};
void
C::test (E e)
{
if (e == X) // breakpoint 2
{
}
}
}
int main()
{
C c;
c.test(A::X);
N::C nc;
nc.test (N::A::X);
return 0;
}

View File

@ -0,0 +1,36 @@
# Copyright 2012 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/>.
# Test searching enum constant symbols derived from base classes.
standard_testfile .cc
if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
return -1
}
if {![runto_main]} {
untested "could not run to main"
return -1
}
gdb_breakpoint [gdb_get_line_number "breakpoint 1" $srcfile]
gdb_continue_to_breakpoint "breakpoint 1"
gdb_test "print X" "= A::X" "Print enum constant X of class A"
gdb_breakpoint [gdb_get_line_number "breakpoint 2" $srcfile]
gdb_continue_to_breakpoint "breakpoint 2"
gdb_test "print X" "= N::A::X" \
"Print enum constant X of class A in namespace N"

View File

@ -1,32 +1,63 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2003-2004, 2007-2012 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/>.
*/
namespace N {
typedef double value_type;
struct Base { typedef int value_type; };
struct Derived : public Base {
void doit (void) const {
int i = 3;
while (i > 0)
--i;
}
};
}
class A {
public:
int a;
int aa;
typedef int value_type;
value_type a;
value_type aa;
A()
{
a=1;
aa=2;
}
int afoo();
int foo();
value_type afoo();
value_type foo();
};
class B {
public:
int b;
int bb;
A::value_type b;
A::value_type bb;
B()
{
b=3;
bb=4;
}
int bfoo();
int foo();
A::value_type bfoo();
A::value_type foo();
};
@ -51,48 +82,48 @@ public:
class D : private A, public B, protected C {
public:
int d;
int dd;
value_type d;
value_type dd;
D()
{
d =7;
dd=8;
}
int dfoo();
int foo();
value_type dfoo();
value_type foo();
};
class E : public A, B, protected C {
public:
int e;
int ee;
value_type e;
value_type ee;
E()
{
e =9;
ee=10;
}
int efoo();
int foo();
value_type efoo();
value_type foo();
};
class F : A, public B, C {
public:
int f;
int ff;
value_type f;
value_type ff;
F()
{
f =11;
ff=12;
}
int ffoo();
int foo();
value_type ffoo();
value_type foo();
};
@ -118,6 +149,19 @@ public:
};
class Z : public A
{
public:
typedef float value_type;
value_type z;
};
class ZZ : public Z
{
public:
value_type zz;
};
class V_base
{
public:
@ -150,27 +194,27 @@ public:
V_derived vderived;
int A::afoo() {
A::value_type A::afoo() {
return 1;
}
int B::bfoo() {
A::value_type B::bfoo() {
return 2;
}
int C::cfoo() {
A::value_type C::cfoo() {
return 3;
}
int D::dfoo() {
D::value_type D::dfoo() {
return 4;
}
int E::efoo() {
E::value_type E::efoo() {
return 5;
}
int F::ffoo() {
F::value_type F::ffoo() {
return 6;
}
@ -178,37 +222,37 @@ int G::gfoo() {
return 77;
}
int A::foo()
A::value_type A::foo()
{
return 7;
}
int B::foo()
A::value_type B::foo()
{
return 8;
}
int C::foo()
A::value_type C::foo()
{
return 9;
}
int D::foo()
D::value_type D::foo()
{
return 10;
}
int E::foo()
E::value_type E::foo()
{
return 11;
}
int F::foo()
F::value_type F::foo()
{
return 12;
@ -236,7 +280,9 @@ int main(void)
E e_instance;
F f_instance;
G g_instance;
Z z_instance;
ZZ zz_instance;
marker1(); // marker1-returns-here
a_instance.a = 20; // marker1-returns-here
@ -251,10 +297,15 @@ int main(void)
e_instance.ee =29;
f_instance.f =30;
f_instance.ff =31;
g_instance.g = 32;
g_instance.gg = 33;
z_instance.z = 34.0;
zz_instance.zz = 35.0;
N::Derived dobj;
N::Derived::value_type d = 1;
N::value_type n = 3.0;
dobj.doit ();
return 0;
}

View File

@ -38,6 +38,18 @@ if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
return -1
}
# Check inheritance of typedefs.
foreach klass {"A" "D" "E" "F"} {
gdb_test "ptype ${klass}::value_type" "type = int"
gdb_test "whatis ${klass}::value_type" "type = int"
gdb_test "p (${klass}::value_type) 0" " = 0"
}
foreach klass {"Z" "ZZ"} {
gdb_test "ptype ${klass}::value_type" "type = float"
gdb_test "whatis ${klass}::value_type" "type = float"
gdb_test "p (${klass}::value_type) 0" " = 0"
}
# Set it up at a breakpoint so we can play with the variable values.
if ![runto 'marker1'] then {
@ -56,11 +68,12 @@ gdb_test "print a_instance" "\\$\[0-9\]+ = \{a = 1, aa = 2\}" "print value of a_
cp_test_ptype_class \
"a_instance" "" "class" "A" \
{
{ field public "int a;" }
{ field public "int aa;" }
{ field public "A::value_type a;" }
{ field public "A::value_type aa;" }
{ method public "A();" }
{ method public "int afoo();" }
{ method public "int foo();" }
{ method public "A::value_type afoo();" }
{ method public "A::value_type foo();" }
{ typedef public "typedef int value_type;" }
}
# class D
@ -77,11 +90,11 @@ cp_test_ptype_class \
{ base "private A" }
{ base "public B" }
{ base "protected C" }
{ field public "int d;" }
{ field public "int dd;" }
{ field public "A::value_type d;" }
{ field public "A::value_type dd;" }
{ method public "D();" }
{ method public "int dfoo();" }
{ method public "int foo();" }
{ method public "A::value_type dfoo();" }
{ method public "A::value_type foo();" }
} \
"" \
{
@ -102,11 +115,11 @@ cp_test_ptype_class \
{ base "public A" }
{ base "private B" }
{ base "protected C" }
{ field public "int e;" }
{ field public "int ee;" }
{ field public "A::value_type e;" }
{ field public "A::value_type ee;" }
{ method public "E();" }
{ method public "int efoo();" }
{ method public "int foo();" }
{ method public "A::value_type efoo();" }
{ method public "A::value_type foo();" }
} \
"" \
{
@ -127,11 +140,11 @@ cp_test_ptype_class \
{ base "private A" }
{ base "public B" }
{ base "private C" }
{ field public "int f;" }
{ field public "int ff;" }
{ field public "A::value_type f;" }
{ field public "A::value_type ff;" }
{ method public "F();" }
{ method public "int ffoo();" }
{ method public "int foo();" }
{ method public "A::value_type ffoo();" }
{ method public "A::value_type foo();" }
}
# class G
@ -193,6 +206,35 @@ gdb_test_multiple "frame" "re-selected 'main' frame after inferior call" {
gdb_test "print g_instance.bfoo()" "\\$\[0-9\]+ = 2" "print value of g_instance.bfoo()"
gdb_test "print g_instance.cfoo()" "\\$\[0-9\]+ = 3" "print value of g_instance.cfoo()"
# Check typedefs of fields
foreach Klass {"C" "G"} {
set klass [string tolower $Klass]
set instance "${klass}_instance"
set var "${instance}.$klass"
gdb_test "whatis $var" "int"
gdb_test "ptype $var" "int"
}
foreach Klass {"A" "B" "D" "E" "F"} {
set klass [string tolower $Klass]
set instance "${klass}_instance"
set var "${instance}.$klass"
gdb_test "whatis $var" "A::value_type"
gdb_test "ptype $var" "int"
if {![string equal $Klass "B"]} {
gdb_test "p (${Klass}::value_type) 0" " = 0"
}
}
foreach Klass {"Z" "ZZ"} {
set klass [string tolower $Klass]
set instance "${klass}_instance"
set var "${instance}.$klass"
gdb_test "whatis $var" "Z::value_type"
gdb_test "ptype $var" "float"
gdb_test "p (${Klass}::value_type) 0" " = 0"
}
# This is a regression test for a bug that caused a crash when trying
# to print the vtbl pointer. We don't care about the output so much
# here (it is tested elsewhere), just that gdb doesn't crash. We test
@ -200,3 +242,16 @@ gdb_test "print g_instance.cfoo()" "\\$\[0-9\]+ = 3" "print value of g_instance.
# path calling get_vptr_fieldno.
gdb_test "ptype vderived" "type = .*"
gdb_test "print vderived" " = {.* inter = 0.*x = 0}"
# Test whether inheritance of typedefs is properly
# reported when stopped.
gdb_test "ptype N::value_type" "type = double"
gdb_test "ptype N::Derived::value_type" "type = int"
# Now run to N::Derived::doit and get the type of "value_type"
if {![runto "N::Derived::doit"]} {
perrro "couldn't run to N::Derived::doit"
continue
}
gdb_test "ptype value_type" "type = int"