From 245a5f0b7429b03566eb3f57a92544218f33393c Mon Sep 17 00:00:00 2001 From: Keith Seitz Date: Fri, 11 Apr 2014 14:17:17 -0700 Subject: [PATCH] Fix c++/16675 -- sizeof reference type should give the size of the referent, not the size of the actual reference variable. --- gdb/ChangeLog | 7 ++++ gdb/c-exp.y | 14 ++++++-- gdb/eval.c | 33 +++++++++++------- gdb/testsuite/ChangeLog | 6 ++++ gdb/testsuite/gdb.cp/cpsizeof.cc | 71 +++++++++++++++++++++++++++++++++++++++ gdb/testsuite/gdb.cp/cpsizeof.exp | 40 ++++++++++++++++++++++ 6 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 gdb/testsuite/gdb.cp/cpsizeof.cc create mode 100644 gdb/testsuite/gdb.cp/cpsizeof.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 48fb279..26bd07b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2014-04-11 Keith Seitz + + PR c++/16675 + * c-exp.y (exp : SIZEOF '(' type ')'): Handle reference types. + * eval.c (evaluate_subexp_for_sizeof): Refactor and handle + reference types. + 2014-04-11 Sanimir Agovic * eval.c (evaluate_subexp_for_sizeof): Add enum noside argument. diff --git a/gdb/c-exp.y b/gdb/c-exp.y index fc79807..f39391c 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -787,14 +787,22 @@ exp : SELECTOR '(' name ')' ; exp : SIZEOF '(' type ')' %prec UNARY - { write_exp_elt_opcode (pstate, OP_LONG); + { struct type *type = $3; + write_exp_elt_opcode (pstate, OP_LONG); write_exp_elt_type (pstate, lookup_signed_typename (parse_language (pstate), parse_gdbarch (pstate), "int")); - CHECK_TYPEDEF ($3); + CHECK_TYPEDEF (type); + + /* $5.3.3/2 of the C++ Standard (n3290 draft) + says of sizeof: "When applied to a reference + or a reference type, the result is the size of + the referenced type." */ + if (TYPE_CODE (type) == TYPE_CODE_REF) + type = check_typedef (TYPE_TARGET_TYPE (type)); write_exp_elt_longcst (pstate, - (LONGEST) TYPE_LENGTH ($3)); + (LONGEST) TYPE_LENGTH (type)); write_exp_elt_opcode (pstate, OP_LONG); } ; diff --git a/gdb/eval.c b/gdb/eval.c index d29960a..2a1c662 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -3030,21 +3030,22 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos, && TYPE_CODE (type) != TYPE_CODE_REF && TYPE_CODE (type) != TYPE_CODE_ARRAY) error (_("Attempt to take contents of a non-pointer value.")); - type = check_typedef (TYPE_TARGET_TYPE (type)); if (is_dynamic_type (type)) type = value_type (value_ind (val)); - return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); + else + type = TYPE_TARGET_TYPE (type); + break; case UNOP_MEMVAL: (*pos) += 3; - type = check_typedef (exp->elts[pc + 1].type); - return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); + type = exp->elts[pc + 1].type; + break; case UNOP_MEMVAL_TYPE: (*pos) += 1; val = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS); - type = check_typedef (value_type (val)); - return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); + type = value_type (val); + break; case OP_VAR_VALUE: type = check_typedef (SYMBOL_TYPE (exp->elts[pc + 2].symbol)); @@ -3055,8 +3056,7 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos, } else (*pos) += 4; - return - value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); + break; /* Deal with the special case if NOSIDE is EVAL_NORMAL and the resulting type of the subscript is a variable length array type. In this case we @@ -3080,8 +3080,8 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos, if (TYPE_RANGE_DATA (type)->flag_bound_evaluated) { val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_NORMAL); - return value_from_longest - (size_type, (LONGEST) TYPE_LENGTH (value_type (val))); + type = value_type (val); + break; } } } @@ -3091,9 +3091,18 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos, default: val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); - return value_from_longest (size_type, - (LONGEST) TYPE_LENGTH (value_type (val))); + type = value_type (val); + break; } + + /* $5.3.3/2 of the C++ Standard (n3290 draft) says of sizeof: + "When applied to a reference or a reference type, the result is + the size of the referenced type." */ + CHECK_TYPEDEF (type); + if (exp->language_defn->la_language == language_cplus + && TYPE_CODE (type) == TYPE_CODE_REF) + type = check_typedef (TYPE_TARGET_TYPE (type)); + return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); } /* Parse a type expression in the string [P..P+LENGTH). */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 4b1eaa1..93f2185 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-04-11 Keith Seitz + + PR c++/16675 + * gdb.cp/cpsizeof.exp: New file. + * gdb.cp/cpsizeof.cc: New file. + 2014-04-11 Sanimir Agovic * mi-vla-c99.exp: New file. diff --git a/gdb/testsuite/gdb.cp/cpsizeof.cc b/gdb/testsuite/gdb.cp/cpsizeof.cc new file mode 100644 index 0000000..0760cfc --- /dev/null +++ b/gdb/testsuite/gdb.cp/cpsizeof.cc @@ -0,0 +1,71 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 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 . */ + +struct Class +{ + int a; + char b; + long c; + + Class () : a (1), b ('2'), c (3) { } +}; + +union Union +{ + Class *kp; + char a; + int b; + long c; +}; + +enum Enum { A, B, C, D }; + +typedef unsigned char a4[4]; +typedef unsigned char a8[8]; +typedef unsigned char a12[12]; +typedef Class c4[4]; +typedef Union u8[8]; +typedef Enum e12[12]; + +#define T(N) \ + N N ## obj; \ + N& N ## _ref = N ## obj; \ + N* N ## p = &(N ## obj); \ + N*& N ## p_ref = N ## p; \ + int size_ ## N = sizeof (N ## _ref); \ + int size_ ## N ## p = sizeof (N ## p_ref); \ + +int +main (void) +{ + T (char); + T (int); + T (long); + T (float); + T (double); + T (a4); + T (a8); + T (a12); + T (Class); + T (Union); + T (Enum); + T (c4); + T (u8); + T (e12); + + return 0; /* break here */ +} diff --git a/gdb/testsuite/gdb.cp/cpsizeof.exp b/gdb/testsuite/gdb.cp/cpsizeof.exp new file mode 100644 index 0000000..f55af9c --- /dev/null +++ b/gdb/testsuite/gdb.cp/cpsizeof.exp @@ -0,0 +1,40 @@ +# sizeof() tests [c++/16675] +# Copyright 2014 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 . + +standard_testfile .cc + +if {[skip_cplus_tests]} { continue } + +if {[prepare_for_testing ${testfile}.exp $testfile $srcfile {debug c++}] } { + return -1 +} + +if {![runto_main]} { + perror "could not run to main" + continue +} + +gdb_breakpoint [gdb_get_line_number "break here"] +gdb_continue_to_breakpoint "break here" + +# Compare sizeof from the compiler and gdb. Do this once with the actual +# type name and once with a reference variable. +foreach v {char int long float double a4 a8 a12 Class Union Enum c4 u8 e12} { + gdb_test "print size_$v == sizeof (${v}&)" "= true" + gdb_test "print size_$v == sizeof (${v}_ref)" "= true" + gdb_test "print size_${v}p == sizeof (${v}*&)" "= true" + gdb_test "print size_${v}p == sizeof (${v}p_ref)" "= true" +} -- 2.7.4