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>
|
2013-11-24 Yao Qi <yao@codesourcery.com>
|
||||||
|
|
||||||
* disasm.c (dis_asm_read_memory): Call target_read_code
|
* disasm.c (dis_asm_read_memory): Call target_read_code
|
||||||
|
|
28
gdb/c-exp.y
28
gdb/c-exp.y
|
@ -2960,13 +2960,39 @@ classify_inner_name (const struct block *block, struct type *context)
|
||||||
|
|
||||||
copy = copy_name (yylval.ssym.stoken);
|
copy = copy_name (yylval.ssym.stoken);
|
||||||
yylval.ssym.sym = cp_lookup_nested_symbol (type, copy, block);
|
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)
|
if (yylval.ssym.sym == NULL)
|
||||||
return ERROR;
|
{
|
||||||
|
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))
|
switch (SYMBOL_CLASS (yylval.ssym.sym))
|
||||||
{
|
{
|
||||||
case LOC_BLOCK:
|
case LOC_BLOCK:
|
||||||
case LOC_LABEL:
|
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;
|
return ERROR;
|
||||||
|
|
||||||
case LOC_TYPEDEF:
|
case LOC_TYPEDEF:
|
||||||
|
|
|
@ -703,6 +703,34 @@ lookup_symbol_file (const char *name,
|
||||||
return sym;
|
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
|
/* Search through the base classes of PARENT_TYPE for a symbol named
|
||||||
NAME in block BLOCK. */
|
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);
|
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. */
|
/* Functions from cp-name-parser.y. */
|
||||||
|
|
||||||
extern struct demangle_parse_info *cp_demangled_name_to_comp
|
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>
|
2013-11-25 Yao Qi <yao@codesourcery.com>
|
||||||
|
|
||||||
* gdb.perf/backtrace.c: New.
|
* 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'"
|
||||||
|
}
|
29
gdb/valops.c
29
gdb/valops.c
|
@ -3128,10 +3128,35 @@ value_struct_elt_for_reference (struct type *domain, int offset,
|
||||||
return value_from_longest
|
return value_from_longest
|
||||||
(lookup_memberptr_type (TYPE_FIELD_TYPE (t, i), domain),
|
(lookup_memberptr_type (TYPE_FIELD_TYPE (t, i), domain),
|
||||||
offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
|
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));
|
return allocate_value (TYPE_FIELD_TYPE (t, i));
|
||||||
else
|
else
|
||||||
error (_("Cannot reference non-static field \"%s\""), name);
|
{
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue