mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-21 01:12:32 +08:00
Fix Rust parser bug with function fields
In Rust, 'obj.f()' is a method call -- but '(obj.f)()' is a call of a function-valued field 'f' in 'obj'. The Rust parser in gdb currently gets this wrong. This is PR rust/24082. The expression and Rust parser rewrites made this simple to fix -- simply wrapping a parenthesized expression in a new operation handles it. This patch has a slight hack because I didn't want to introduce a new exp_opcode enumeration constant just for this. IMO this doesn't matter, since we should work toward removing dependencies on these opcodes anyway; but let me know what you think of this. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=24082
This commit is contained in:
parent
a92613915e
commit
c1f5e54825
@ -197,6 +197,33 @@ class rust_aggregate_operation
|
||||
{ return OP_AGGREGATE; }
|
||||
};
|
||||
|
||||
/* Rust parenthesized operation. This is needed to distinguish
|
||||
between 'obj.f()', which is a method call, and '(obj.f)()', which
|
||||
is a call of a function-valued field 'f'. */
|
||||
class rust_parenthesized_operation
|
||||
: public tuple_holding_operation<operation_up>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit rust_parenthesized_operation (operation_up op)
|
||||
: tuple_holding_operation (std::move (op))
|
||||
{
|
||||
}
|
||||
|
||||
value *evaluate (struct type *expect_type,
|
||||
struct expression *exp,
|
||||
enum noside noside) override
|
||||
{
|
||||
return std::get<0> (m_storage)->evaluate (expect_type, exp, noside);
|
||||
}
|
||||
|
||||
enum exp_opcode opcode () const override
|
||||
{
|
||||
/* A lie but this isn't worth introducing a new opcode for. */
|
||||
return UNOP_PLUS;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace expr */
|
||||
|
||||
#endif /* RUST_EXP_H */
|
||||
|
@ -1105,7 +1105,7 @@ rust_parser::parse_tuple ()
|
||||
{
|
||||
/* Parenthesized expression. */
|
||||
lex ();
|
||||
return expr;
|
||||
return make_operation<rust_parenthesized_operation> (std::move (expr));
|
||||
}
|
||||
|
||||
std::vector<operation_up> ops;
|
||||
|
38
gdb/testsuite/gdb.rust/fnfield.exp
Normal file
38
gdb/testsuite/gdb.rust/fnfield.exp
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2022 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/>.
|
||||
|
||||
# Test trait object printing.
|
||||
|
||||
load_lib rust-support.exp
|
||||
if {[skip_rust_tests]} {
|
||||
continue
|
||||
}
|
||||
|
||||
standard_testfile .rs
|
||||
if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug rust}]} {
|
||||
return -1
|
||||
}
|
||||
|
||||
set line [gdb_get_line_number "set breakpoint here"]
|
||||
if {![runto ${srcfile}:$line]} {
|
||||
untested "could not run to breakpoint"
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test "print foo.f()" " = 6" "call impl function"
|
||||
gdb_test "print (foo.f)()" " = 5" "call function field"
|
||||
gdb_test "print foo.g()" " = 7" "call impl function g"
|
||||
gdb_test "print (foo.g)()" "There is no member named g." \
|
||||
"cannot call g with parens"
|
39
gdb/testsuite/gdb.rust/fnfield.rs
Normal file
39
gdb/testsuite/gdb.rust/fnfield.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2022 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/>.
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
fn five() -> i32 { 5 }
|
||||
|
||||
fn main() {
|
||||
let foo = Foo {x: 5, f: five};
|
||||
foo.print(); // set breakpoint here
|
||||
println!("Hello, world! {}, {}, {}", foo.f(), (foo.f)(),
|
||||
foo.g ());
|
||||
}
|
||||
|
||||
struct Foo {
|
||||
x :i32,
|
||||
f: fn () -> i32,
|
||||
}
|
||||
|
||||
impl Foo {
|
||||
fn print(&self) {
|
||||
println!("hello {}", self.x)
|
||||
}
|
||||
|
||||
fn f(&self) -> i32 { 6 }
|
||||
fn g(&self) -> i32 { 7 }
|
||||
}
|
Loading…
Reference in New Issue
Block a user