diff --git a/gdb/eval.c b/gdb/eval.c index 655ea22..9e58caa 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -685,6 +685,7 @@ evaluate_subexp_standard (struct type *expect_type, struct type *type; int nargs; struct value **argvec; + struct type *callable_type = NULL; int code; int ix; long mem_offset; @@ -1502,21 +1503,48 @@ evaluate_subexp_standard (struct type *expect_type, } else { - /* Non-method function call. */ + /* It could either be a normal function call, or an overloaded + operator() call. */ + struct value *callable_value; + int fptr = 0, struct_or_union = 0, internal_func = 0; save_pos1 = *pos; tem = 1; - /* If this is a C++ function wait until overload resolution. */ - if (op == OP_VAR_VALUE - && overload_resolution - && (exp->language_defn->la_language == language_cplus)) + callable_value = evaluate_subexp_with_coercion (exp, pos, noside); + callable_type = check_typedef (value_type (callable_value)); + if (TYPE_CODE (callable_type) == TYPE_CODE_PTR) { - (*pos) += 4; /* Skip the evaluation of the symbol. */ + callable_type = check_typedef (TYPE_TARGET_TYPE (callable_type)); + if (TYPE_CODE (callable_type) != TYPE_CODE_FUNC) + error (_("Operand to '()' operator is not a callable.")); + fptr = 1; + } + else if (exp->language_defn->la_language == language_cplus + && class_or_union_p (callable_type)) + struct_or_union = 1; /* There could be an operator() method. */ + else if (TYPE_CODE (callable_type) == TYPE_CODE_INTERNAL_FUNCTION) + internal_func = 1; + else if (TYPE_CODE (callable_type) == TYPE_CODE_FUNC) + ; /* Normal function call. */ + else + error (_("Operand to '()' operator is not a callable.")); + + /* If this is C++, wait until overload resolution. */ + if (!fptr && !internal_func + && exp->language_defn->la_language == language_cplus + && (overload_resolution || struct_or_union)) + { + if (struct_or_union) + { + arg2 = value_addr (callable_value); + nargs++; + tem = 2; + } argvec[0] = NULL; } else { - argvec[0] = evaluate_subexp_with_coercion (exp, pos, noside); + argvec[0] = callable_value; type = value_type (argvec[0]); if (type && TYPE_CODE (type) == TYPE_CODE_PTR) type = TYPE_TARGET_TYPE (type); @@ -1571,10 +1599,11 @@ evaluate_subexp_standard (struct type *expect_type, } if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR - || (op == OP_SCOPE && function_name != NULL)) + || (op == OP_SCOPE && function_name != NULL) + || (callable_type != NULL && class_or_union_p (callable_type))) { int static_memfuncp; - char *tstr; + const char *tstr; /* Method invocation: stuff "this" as first parameter. If the method turns out to be static we undo this below. */ @@ -1582,8 +1611,13 @@ evaluate_subexp_standard (struct type *expect_type, if (op != OP_SCOPE) { - /* Name of method from expression. */ - tstr = &exp->elts[pc2 + 2].string; + if (callable_type == NULL) + { + /* Name of method from expression. */ + tstr = &exp->elts[pc2 + 2].string; + } + else + tstr = "operator()"; } else tstr = function_name; diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 8e44b7c..de2ef2b 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -2513,6 +2513,15 @@ class_types_same_p (const struct type *a, const struct type *b) && !strcmp (TYPE_NAME (a), TYPE_NAME (b)))); } +/* Return true is T is a class or a union. False otherwise. */ + +int +class_or_union_p (const struct type *t) +{ + return (TYPE_CODE (t) == TYPE_CODE_STRUCT + || TYPE_CODE (t) == TYPE_CODE_UNION); +} + /* If BASE is an ancestor of DCLASS return the distance between them. otherwise return -1; eg: diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 14a1f08..d32c97c 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -1742,6 +1742,8 @@ extern int get_array_bounds (struct type *type, LONGEST *low_bound, extern int class_types_same_p (const struct type *, const struct type *); +extern int class_or_union_p (const struct type *t); + extern int is_ancestor (struct type *, struct type *); extern int is_public_ancestor (struct type *, struct type *); diff --git a/gdb/testsuite/gdb.cp/member-ptr.exp b/gdb/testsuite/gdb.cp/member-ptr.exp index c13b852..649fe89 100644 --- a/gdb/testsuite/gdb.cp/member-ptr.exp +++ b/gdb/testsuite/gdb.cp/member-ptr.exp @@ -389,7 +389,7 @@ gdb_test "ptype diamond.*diamond_pfunc_ptr" \ # call the member pointer as a normal pointer-to-function. gdb_test "print diamond.*diamond_pfunc_ptr (20)" \ - "Invalid data type for function to be called." + "Operand to '\\(\\)' operator is not a callable\\." # With parentheses, it is valid. @@ -665,7 +665,7 @@ gdb_test "print base_vpmf" \ # Make sure we parse this correctly; it's invalid. gdb_test "print diamond.*left_vpmf ()" \ - "Invalid data type for function to be called\\." + "Operand to '\\(\\)' operator is not a callable\\." # NULL pointer to member tests. gdb_test "print null_pmi" "$vhn = NULL" diff --git a/gdb/testsuite/gdb.cp/paren-op.cc b/gdb/testsuite/gdb.cp/paren-op.cc new file mode 100644 index 0000000..89a085a --- /dev/null +++ b/gdb/testsuite/gdb.cp/paren-op.cc @@ -0,0 +1,60 @@ +/* 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 S +{ + int operator() (int x); +}; + +int +S::operator() (int x) +{ + return x + 5; +} + +int +s (int a, int b) +{ + return a + b; +} + +int (*s1_ptr) (int, int) = &s; + +int +s (int a) +{ + return a * a; +} + +union U +{ + int operator () (int x); +}; + +int +U::operator() (int x) +{ + return x + 10; +} + +int main () { + S s; + U u; + int i = 10; + + return 0; /* Break here */ +} diff --git a/gdb/testsuite/gdb.cp/paren-op.exp b/gdb/testsuite/gdb.cp/paren-op.exp new file mode 100644 index 0000000..152b8c9 --- /dev/null +++ b/gdb/testsuite/gdb.cp/paren-op.exp @@ -0,0 +1,37 @@ +# 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 . + +# This file is part of the gdb testsuite + +if {[skip_cplus_tests]} { continue } + +standard_testfile .cc + +if {[prepare_for_testing $testfile.exp $testfile $srcfile \ + {debug c++ additional_flags=-std=c++11}]} { + return -1 +} + +if {![runto_main]} { + return -1 +} + +gdb_breakpoint [gdb_get_line_number "Break here"] +gdb_continue_to_breakpoint "Break here" + +gdb_test "p s(12340)" ".* = 12345" "p s()" +gdb_test "p u(446)" ".* = 456" "p u()" +gdb_test "p i(789)" "Operand to '\\(\\)' operator is not a callable\\." "p i()" +gdb_test "p s1_ptr(500, 67)" ".* = 567" "p s1_ptr()"