PR c++/14819: Explicit class:: inside class scope does not work

https://sourceware.org/ml/gdb-patches/2013-11/msg00102.html
This commit is contained in:
Keith Seitz 2013-11-25 13:37:08 -08:00
parent b02677b904
commit f7e3ecae9f
8 changed files with 370 additions and 3 deletions

View file

@ -1,3 +1,15 @@
2013-11-25 Keith Seitz <keiths@redhat.com>
PR c++/14819
* c-exp.y (classify_inner_name): If no matching symbol was
found, try looking up the token as a base class.
Likewise if a constructor was found.
* cp-namespace.c (find_type_baseclass_by_name): New function.
* cp-support.h (find_type_baseclass_by_name): Declare.
* valops.c (value_struct_elt_for_reference): If we get
a non-static field, try to get a value based on the
current instance, if any.
2013-11-24 Yao Qi <yao@codesourcery.com>
* disasm.c (dis_asm_read_memory): Call target_read_code

View file

@ -2960,13 +2960,39 @@ classify_inner_name (const struct block *block, struct type *context)
copy = copy_name (yylval.ssym.stoken);
yylval.ssym.sym = cp_lookup_nested_symbol (type, copy, block);
/* If no symbol was found, search for a matching base class named
COPY. This will allow users to enter qualified names of class members
relative to the `this' pointer. */
if (yylval.ssym.sym == NULL)
{
struct type *base_type = find_type_baseclass_by_name (type, copy);
if (base_type != NULL)
{
yylval.tsym.type = base_type;
return TYPENAME;
}
return ERROR;
}
switch (SYMBOL_CLASS (yylval.ssym.sym))
{
case LOC_BLOCK:
case LOC_LABEL:
/* cp_lookup_nested_symbol might have accidentally found a constructor
named COPY when we really wanted a base class of the same name.
Double-check this case by looking for a base class. */
{
struct type *base_type = find_type_baseclass_by_name (type, copy);
if (base_type != NULL)
{
yylval.tsym.type = base_type;
return TYPENAME;
}
}
return ERROR;
case LOC_TYPEDEF:

View file

@ -703,6 +703,34 @@ lookup_symbol_file (const char *name,
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. */

View file

@ -220,6 +220,11 @@ extern struct symbol *cp_lookup_nested_symbol (struct type *parent_type,
struct type *cp_lookup_transparent_type (const char *name);
/* See description in cp-namespace.c. */
struct type *find_type_baseclass_by_name (struct type *parent_type,
const char *name);
/* Functions from cp-name-parser.y. */
extern struct demangle_parse_info *cp_demangled_name_to_comp

View file

@ -1,3 +1,9 @@
2013-11-25 Keith Seitz <keiths@redhat.com>
PR c++/14819
* gdb.cp/impl-this.cc: New file.
* gdb.cp/impl-this.exp: New file.
2013-11-25 Yao Qi <yao@codesourcery.com>
* gdb.perf/backtrace.c: New.

View file

@ -0,0 +1,135 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2013 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/>. */
#ifdef DEBUG
#include <stdio.h>
#endif
template <typename T>
class A
{
public:
T i;
T z;
A () : i (1), z (10) {}
};
template <typename T>
class B : public virtual A<T>
{
public:
T i;
T common;
B () : i (2), common (200) {}
};
typedef B<int> Bint;
class C : public virtual A<int>
{
public:
int i;
int c;
int common;
C () : i (3), c (30), common (300) {}
};
class BB : public A<int>
{
public:
int i;
BB () : i (20) {}
};
class CC : public A<int>
{
public:
int i;
CC () : i (30) {}
};
class Ambig : public BB, public CC
{
public:
int i;
Ambig () : i (1000) {}
};
class D : public Bint, public C
{
public:
int i;
int x;
Ambig am;
D () : i (4), x (40) {}
#ifdef DEBUG
#define SUM(X) \
do \
{ \
sum += (X); \
printf ("" #X " = %d\n", (X)); \
} \
while (0)
#else
#define SUM(X) sum += (X)
#endif
int
f (void)
{
int sum = 0;
SUM (i);
SUM (D::i);
SUM (D::B<int>::i);
SUM (B<int>::i);
SUM (D::C::i);
SUM (C::i);
SUM (D::B<int>::A<int>::i);
SUM (B<int>::A<int>::i);
SUM (A<int>::i);
SUM (D::C::A<int>::i);
SUM (C::A<int>::i);
SUM (D::x);
SUM (x);
SUM (D::C::c);
SUM (C::c);
SUM (c);
SUM (D::A<int>::i);
SUM (Bint::i);
//SUM (D::Bint::i);
//SUM (D::Bint::A<int>::i);
SUM (Bint::A<int>::i);
// ambiguous: SUM (common);
SUM (B<int>::common);
SUM (C::common);
SUM (am.i);
// ambiguous: SUM (am.A<int>::i);
return sum;
}
};
int
main (void)
{
Bint b;
D d;
return d.f () + b.i;
}

View file

@ -0,0 +1,130 @@
# Copyright 2013 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/>.
# This file is part of the gdb testsuite
# Test expressions which assume an implicit "this" with a qualified
# name.
if {[skip_cplus_tests]} { continue }
standard_testfile .cc
if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
return -1
}
# First test expressions when there is no context.
with_test_prefix "before run" {
gdb_test "print i" "No symbol \"i\" in current context."
gdb_test "print D::i" "Cannot reference non-static field \"i\""
gdb_test "print D::B<int>::i" "Cannot reference non-static field \"i\""
gdb_test "print B<int>::i" "Cannot reference non-static field \"i\""
gdb_test "print D::C::i" "Cannot reference non-static field \"i\""
gdb_test "print C::i" "Cannot reference non-static field \"i\""
gdb_test "print D::B<int>::A<int>::i" \
"Cannot reference non-static field \"i\""
gdb_test "print B<int>::A<int>::i" "Cannot reference non-static field \"i\""
gdb_test "print A<int>::i" "Cannot reference non-static field \"i\""
gdb_test "print D::C::A<int>::i" "Cannot reference non-static field \"i\""
gdb_test "print C::A<int>::i" "Cannot reference non-static field \"i\""
gdb_test "print D::x" "Cannot reference non-static field \"x\""
gdb_test "print x" "No symbol \"x\" in current context."
gdb_test "print D::C::c" "Cannot reference non-static field \"c\""
gdb_test "print C::c" "Cannot reference non-static field \"c\""
gdb_test "print c" "No symbol \"c\" in current context."
gdb_test "print D::A<int>::i" "Cannot reference non-static field \"i\""
}
# Run to D::f.
if {![runto_main]} {
perror "couldn't run to main"
continue
}
gdb_breakpoint "D::f"
gdb_continue_to_breakpoint "continue to D::f"
# Now test valid expressions in the class hierarchy for D.
with_test_prefix "at D::f (valid expressions)" {
gdb_test "print i" "= 4"
gdb_test "print D::i" "= 4"
gdb_test "print D::B<int>::i" "= 2"
gdb_test "print B<int>::i" "= 2"
gdb_test "print D::Bint::i" \
"No type \"Bint\" within class or namespace \"D\"."
gdb_test "print Bint::i" "= 2"
gdb_test "print D::C::i" "= 3"
gdb_test "print C::i" "= 3"
gdb_test "print D::B<int>::A<int>::i" "= 1"
gdb_test "print B<int>::A<int>::i" "= 1"
gdb_test "print D::Bint::A<int>::i" \
"No type \"Bint\" within class or namespace \"D\"."
gdb_test "print Bint::A<int>::i" "= 1"
gdb_test "print A<int>::i" "= 1"
gdb_test "print D::C::A<int>::i" "= 1"
gdb_test "print C::A<int>::i" "= 1"
gdb_test "print D::x" "= 40"
gdb_test "print x" "= 40"
gdb_test "print D::C::c" "= 30"
gdb_test "print C::c" "= 30"
gdb_test "print c" "= 30"
gdb_test "print D::A<int>::i" "= 1"
}
# Test some invalid expressions
with_test_prefix "at D::f (invalid expressions)" {
gdb_test "print D::B<int>::c" "There is no field named c"
gdb_test "print D::B<int>::A<int>::c" "There is no field named c"
gdb_test "print D::Bint::c" \
"No type \"Bint\" within class or namespace \"D\"."
gdb_test "print D::Bint::A<int>::c" \
"No type \"Bint\" within class or namespace \"D\"."
gdb_test "print D::C::A<int>::c" "There is no field named c"
gdb_test "print B<int>::c" "There is no field named c"
gdb_test "print B<int>::A<int>::c" "There is no field named c"
gdb_test "print Bint::c" "There is no field named c"
gdb_test "print Bint::A<int>::c" "There is no field named c"
gdb_test "print C::A<int>::c" "There is no field named c"
gdb_test "print D::B<int>::x" "There is no field named x"
gdb_test "print D::B<int>::A<int>::x" "There is no field named x"
gdb_test "print D::Bint::x" \
"No type \"Bint\" within class or namespace \"D\"."
gdb_test "print D::Bint::A<int>::x" \
"No type \"Bint\" within class or namespace \"D\"."
gdb_test "print B<int>::x" "There is no field named x"
gdb_test "print B<int>::A<int>::x" "There is no field named x"
gdb_test "print Bint::x" "There is no field named x"
gdb_test "print Bint::A<int>::x" "There is no field named x"
gdb_test "print D::C::x" "There is no field named x"
gdb_test "print C::x" "There is no field named x"
gdb_test "print D::C::A<int>::x" "There is no field named x"
gdb_test "print C::A<int>::x" "There is no field named x"
}
# Test some ambiguous names
with_test_prefix "at D::f (ambiguous names)" {
gdb_test "print B<int>::common" " = 200"
gdb_test "print Bint::common" " = 200"
gdb_test "print C::common" " = 300"
gdb_test "print am.i" " = 1000"
gdb_test "print am.A<int>::i" \
"base class 'A<int>' is ambiguous in type 'Ambig'"
gdb_test "print am.BB::A<int>::i" \
"base class 'A<int>' is ambiguous in type 'Ambig'"
gdb_test "print am.CC::A<int>::i" \
"base class 'A<int>' is ambiguous in type 'Ambig'"
}

View file

@ -3128,12 +3128,37 @@ value_struct_elt_for_reference (struct type *domain, int offset,
return value_from_longest
(lookup_memberptr_type (TYPE_FIELD_TYPE (t, i), domain),
offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
else if (noside == EVAL_AVOID_SIDE_EFFECTS)
else if (noside != EVAL_NORMAL)
return allocate_value (TYPE_FIELD_TYPE (t, i));
else
{
/* Try to evaluate NAME as a qualified name with implicit
this pointer. In this case, attempt to return the
equivalent to `this->*(&TYPE::NAME)'. */
v = value_of_this_silent (current_language);
if (v != NULL)
{
struct value *ptr;
long mem_offset;
struct type *type, *tmp;
ptr = value_aggregate_elt (domain, name, NULL, 1, noside);
type = check_typedef (value_type (ptr));
gdb_assert (type != NULL
&& TYPE_CODE (type) == TYPE_CODE_MEMBERPTR);
tmp = lookup_pointer_type (TYPE_DOMAIN_TYPE (type));
v = value_cast_pointers (tmp, v, 1);
mem_offset = value_as_long (ptr);
tmp = lookup_pointer_type (TYPE_TARGET_TYPE (type));
result = value_from_pointer (tmp,
value_as_long (v) + mem_offset);
return value_ind (result);
}
error (_("Cannot reference non-static field \"%s\""), name);
}
}
}
/* C++: If it was not found as a data field, then try to return it
as a pointer to a method. */