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:
parent
b02677b904
commit
f7e3ecae9f
8 changed files with 370 additions and 3 deletions
|
@ -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
|
||||
|
|
26
gdb/c-exp.y
26
gdb/c-exp.y
|
@ -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:
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
135
gdb/testsuite/gdb.cp/impl-this.cc
Normal file
135
gdb/testsuite/gdb.cp/impl-this.cc
Normal 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;
|
||||
}
|
130
gdb/testsuite/gdb.cp/impl-this.exp
Normal file
130
gdb/testsuite/gdb.cp/impl-this.exp
Normal 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'"
|
||||
}
|
27
gdb/valops.c
27
gdb/valops.c
|
@ -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. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue