From: Guinevere Larsen <blarsen@redhat.com>
To: Hannes Domani <ssbssa@yahoo.de>, gdb-patches@sourceware.org
Subject: Re: [PATCH] Allow calling of user-defined function call operators
Date: Thu, 25 Apr 2024 15:34:13 -0300 [thread overview]
Message-ID: <28251b39-dda2-4da6-8bb6-2a5d81ef39df@redhat.com> (raw)
In-Reply-To: <20240421124954.3285-1-ssbssa@yahoo.de>
On 4/21/24 09:49, Hannes Domani wrote:
> Currently it's not possible to call user-defined function call
> operators, at least not without specifying operator() directly:
> ```
> (gdb) l 1
> 1 struct S {
> 2 int operator() (int x) { return x + 5; }
> 3 };
> 4
> 5 int main () {
> 6 S s;
> 7
> 8 return s(23);
> 9 }
> (gdb) p s(10)
> Invalid data type for function to be called.
> (gdb) p s.operator()(10)
> $1 = 15
> ```
>
> This now looks if an user-defined call operator is available when
> trying to 'call' a struct value, and calls it instead, making this
> possible:
> ```
> (gdb) p s(10)
> $1 = 15
> ```
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=12213
Thanks for this fix, this has been a long time coming.
I have one, possibly big, question.
> ---
> gdb/eval.c | 46 +++++++++++++++++++++++++++-----
> gdb/testsuite/gdb.cp/userdef.cc | 18 +++++++++++++
> gdb/testsuite/gdb.cp/userdef.exp | 4 +++
> 3 files changed, 62 insertions(+), 6 deletions(-)
>
> diff --git a/gdb/eval.c b/gdb/eval.c
> index 6b752e70635..e737774ca28 100644
> --- a/gdb/eval.c
> +++ b/gdb/eval.c
> @@ -664,14 +664,34 @@ operation::evaluate_funcall (struct type *expect_type,
>
> value *callee = evaluate_with_coercion (exp, noside);
> struct type *type = callee->type ();
> - if (type->code () == TYPE_CODE_PTR)
> - type = type->target_type ();
> - for (int i = 0; i < args.size (); ++i)
> +
> + /* If the callee is a struct, there might be a user-defined function call
> + operator that should be used instead. */
> + if (overload_resolution
> + && exp->language_defn->la_language == language_cplus
> + && check_typedef (type)->code () == TYPE_CODE_STRUCT)
> {
> - if (i < type->num_fields ())
> - vals[i] = args[i]->evaluate (type->field (i).type (), exp, noside);
> - else
> + for (int i = 0; i < args.size (); ++i)
> vals[i] = args[i]->evaluate_with_coercion (exp, noside);
> +
> + vals.insert (vals.begin(), value_addr (callee));
> + int static_memfuncp;
> + find_overload_match (vals, "operator()", METHOD, &vals[0], nullptr,
> + &callee, nullptr, &static_memfuncp, 0, noside);
> + if (static_memfuncp)
> + vals.erase (vals.begin ());
> + }
> + else
> + {
> + if (type->code () == TYPE_CODE_PTR)
> + type = type->target_type ();
> + for (int i = 0; i < args.size (); ++i)
> + {
> + if (i < type->num_fields ())
> + vals[i] = args[i]->evaluate (type->field (i).type (), exp, noside);
> + else
> + vals[i] = args[i]->evaluate_with_coercion (exp, noside);
> + }
This change had me confused for quite a bit. I couldn't figure out why
the base operation::evaluate_funcall. The problem seems to be that if
command used is something less straightforward, like "print (foo+bar)
(args)", we will use the evaluate_funcall of the operation (in this
case, add_operation) instead of var_value_operation's. Did I understand
it correctly?
Assuming I did, I don't think this code duplication is the best way to
go. Especially seeing as there are some differences in those functions
already, and if all that it takes to defeat out expression parser is use
(*&foo) or (a + b) (), we probably already have latent bugs in this
area. I don't know how to verify it, though, because I really don't
understand the code differences.
Ideally, I think the best way would be to put all the code in
var_value_operation::evaluate_funcall, but to do this, you'd need to be
able to find a way to call the resulting var_value_operation's function
from all relevant operations, which is probably a lot.
Another option is to just park all the logic in
operation::evaluate_funcall, so we're always using the correct function.
This comes with the cost of being very confusing in a couple of months
to a year.
Does this make sense?
--
Cheers,
Guinevere Larsen
She/Her/Hers
> }
>
> return evaluate_subexp_do_call (exp, noside, callee, vals,
> @@ -702,6 +722,20 @@ var_value_operation::evaluate_funcall (struct type *expect_type,
> value *callee = evaluate_var_value (noside, std::get<0> (m_storage).block,
> symp);
>
> + /* If the callee is a struct, there might be a user-defined function call
> + operator that should be used instead. */
> + if (overload_resolution
> + && exp->language_defn->la_language == language_cplus
> + && check_typedef (callee->type ())->code () == TYPE_CODE_STRUCT)
> + {
> + argvec.insert (argvec.begin(), value_addr (callee));
> + int static_memfuncp;
> + find_overload_match (argvec, "operator()", METHOD, &argvec[0], nullptr,
> + &callee, nullptr, &static_memfuncp, 0, noside);
> + if (static_memfuncp)
> + argvec.erase (argvec.begin ());
> + }
> +
> return evaluate_subexp_do_call (exp, noside, callee, argvec,
> nullptr, expect_type);
> }
> diff --git a/gdb/testsuite/gdb.cp/userdef.cc b/gdb/testsuite/gdb.cp/userdef.cc
> index 774191726f3..48507551079 100644
> --- a/gdb/testsuite/gdb.cp/userdef.cc
> +++ b/gdb/testsuite/gdb.cp/userdef.cc
> @@ -68,6 +68,9 @@ A1 operator++(int);
> A1 operator--();
> A1 operator--(int);
>
> +int operator()();
> +int operator()(int);
> +
> };
>
>
> @@ -293,6 +296,16 @@ ostream& operator<<(ostream& outs, A1 one)
> return (outs << endl << "x = " << one.x << endl << "y = " << one.y << endl << "-------" << endl);
> }
>
> +int A1::operator()()
> +{
> + return x + y;
> +}
> +
> +int A1::operator()(int value)
> +{
> + return value * (x + y);
> +}
> +
> class A2 {
> public:
> A2 operator+();
> @@ -404,6 +417,11 @@ int main (void)
> ++three;
> cout << "preinc " << three;
>
> + val = two();
> + cout << "funcall " << val << endl;
> + val = two(10);
> + cout << "funcall 2 " << val << endl;
> +
> (*c).z = 1;
>
> return 0;
> diff --git a/gdb/testsuite/gdb.cp/userdef.exp b/gdb/testsuite/gdb.cp/userdef.exp
> index e96636bef0c..667bded6b83 100644
> --- a/gdb/testsuite/gdb.cp/userdef.exp
> +++ b/gdb/testsuite/gdb.cp/userdef.exp
> @@ -119,6 +119,10 @@ gdb_test "print one += 7" "\\\$\[0-9\]* = {x = 9, y = 10}"
>
> gdb_test "print two = one" "\\\$\[0-9\]* = {x = 9, y = 10}"
>
> +gdb_test "print two()" " = 19"
> +gdb_test "print two(10)" " = 190"
> +gdb_test "print (*&two)(2)" " = 38"
> +
> # Check that GDB tolerates whitespace in operator names.
> gdb_test "break A2::operator+" ".*Breakpoint $decimal at.*"
> gdb_test "break A2::operator +" ".*Breakpoint $decimal at.*"
next prev parent reply other threads:[~2024-04-25 18:34 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20240421124954.3285-1-ssbssa.ref@yahoo.de>
2024-04-21 12:49 ` Hannes Domani
2024-04-25 18:34 ` Guinevere Larsen [this message]
2024-04-27 16:43 ` Hannes Domani
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=28251b39-dda2-4da6-8bb6-2a5d81ef39df@redhat.com \
--to=blarsen@redhat.com \
--cc=gdb-patches@sourceware.org \
--cc=ssbssa@yahoo.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).