From patchwork Thu Nov 20 16:56:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siva Chandra Reddy X-Patchwork-Id: 3814 Received: (qmail 18044 invoked by alias); 20 Nov 2014 16:56:16 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 18034 invoked by uid 89); 20 Nov 2014 16:56:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mail-oi0-f48.google.com Received: from mail-oi0-f48.google.com (HELO mail-oi0-f48.google.com) (209.85.218.48) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Thu, 20 Nov 2014 16:56:14 +0000 Received: by mail-oi0-f48.google.com with SMTP id u20so2311245oif.35 for ; Thu, 20 Nov 2014 08:56:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:date:message-id:subject:from:to :content-type; bh=gbaS5nmPVggbhTot9RQ06GT7gcXfmHRlW2DFRNIzNaw=; b=QRCAjzJS5fhjfW5J+eQkothMd78B0UYujD0kkLIV/muUllk7+cNBs+XFJGpb6Muf8D qczKd2LHN4NFCKJ2BczW6zTTIn96CjQeEQszQ5Wwrt2Me14MDgwOzqRNChFoTxiY8pw/ GUxTOH4aIeMX6s0q3MbseQXFTDhJYhEkZdqbgqyuM1hMDo6K04XLNAB5sUUiMUybPbBW wIGe46+0wH0IgbllnEl/8xCDYPur/xasA1g1z+buoNrdErvaXlk4UQ16vZluSyBpq+vx OKPcpfhdR1XZMRMglkdxny7f/hM5twyiYpedJO+zxcM6Qn+v3vOqbrcKuq931RCdCxjB UgmQ== X-Gm-Message-State: ALoCoQmmgIyDYINkP99zW3NJgTTjCE+aMAqaBo1xt1z86YDfTVzAAyzBElF65J9LC8IhCahYWNtG MIME-Version: 1.0 X-Received: by 10.60.67.233 with SMTP id q9mr42846354oet.30.1416502572317; Thu, 20 Nov 2014 08:56:12 -0800 (PST) Received: by 10.202.177.3 with HTTP; Thu, 20 Nov 2014 08:56:12 -0800 (PST) Date: Thu, 20 Nov 2014 08:56:12 -0800 Message-ID: Subject: [PATCH] Enable invoking overloaded operator() method on class and union values. From: Siva Chandra To: gdb-patches X-IsSubscribed: yes Hello, The attached patch enables invoking overloaded operator() method on class and union values when evaluating expressions. [I expected that once this feature is in, invoking c++ lambdas would also be possible naturally. However, It does not happen and I am working on that.] gdb/ChangeLog: 2014-11-20 Siva Chandra Reddy * eval.c (evaluate_subexp_standard): Extend handling of OP_FUNCALL operation to enable invoking overloaded operator() methods. * gdbtypes.c (class_or_union_p): New function. * gdbtypes.h (class_or_union_p): Declare. gdb/testsuite/ChangeLog: 2014-11-20 Siva Chandra Reddy * gdb.cp/member-ptr.exp: Modify expected pattern of "print diamond.*diamond_pfunc_ptr (20)" and "print diamond.*left_vpmf ()". * gdb.cp/paren-op.cc: New file. * gdb.cp/paren-op.exp: New file. Regression tested on x86_64 GNU/Linux. Thank you, Siva Chandra 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()"