diff options
-rw-r--r-- | gdb/completer.h | 19 | ||||
-rw-r--r-- | gdb/cp-support.c | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/cpcompletion.cc | 23 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/cpcompletion.exp | 2 | ||||
-rw-r--r-- | gdb/testsuite/gdb.rust/completion.exp | 33 | ||||
-rw-r--r-- | gdb/testsuite/gdb.rust/completion.rs | 19 | ||||
-rw-r--r-- | gdb/utils.c | 2 |
7 files changed, 104 insertions, 1 deletions
diff --git a/gdb/completer.h b/gdb/completer.h index 8b4ad8e..67d2fbf 100644 --- a/gdb/completer.h +++ b/gdb/completer.h @@ -145,7 +145,12 @@ public: /* Mark the range between [BEGIN, END) as ignored. */ void mark_ignored_range (const char *begin, const char *end) - { m_ignored_ranges.emplace_back (begin, end); } + { + gdb_assert (begin < end); + gdb_assert (m_ignored_ranges.empty () + || m_ignored_ranges.back ().second < begin); + m_ignored_ranges.emplace_back (begin, end); + } /* Get the resulting LCD, after a successful match. If there are ignored ranges, then this builds a new string with the ignored @@ -160,9 +165,14 @@ public: { m_finished_storage.clear (); + gdb_assert (m_ignored_ranges.back ().second + <= (m_match + strlen (m_match))); + const char *prev = m_match; for (const auto &range : m_ignored_ranges) { + gdb_assert (prev < range.first); + gdb_assert (range.second > range.first); m_finished_storage.append (prev, range.first); prev = range.second; } @@ -179,6 +189,13 @@ public: m_ignored_ranges.clear (); } + /* Return true if this object has had no match data set since its + creation, or the last call to clear. */ + bool empty () const + { + return m_match == nullptr && m_ignored_ranges.empty (); + } + private: /* The completion match result for LCD. This is usually either a pointer into to a substring within a symbol's name, or to the diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 78eacd0..f39c5d0 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -1776,6 +1776,8 @@ cp_symbol_name_matches_1 (const char *symbol_search_name, completion_match_for_lcd *match_for_lcd = (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL); + gdb_assert (match_for_lcd == nullptr || match_for_lcd->empty ()); + while (true) { if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len, @@ -1809,6 +1811,11 @@ cp_symbol_name_matches_1 (const char *symbol_search_name, return true; } + /* Clear match_for_lcd so the next strncmp_iw_with_mode call starts + from scratch. */ + if (match_for_lcd != nullptr) + match_for_lcd->clear (); + unsigned int len = cp_find_first_component (sname); if (sname[len] == '\0') diff --git a/gdb/testsuite/gdb.cp/cpcompletion.cc b/gdb/testsuite/gdb.cp/cpcompletion.cc index 54ddaaf..b854d81 100644 --- a/gdb/testsuite/gdb.cp/cpcompletion.cc +++ b/gdb/testsuite/gdb.cp/cpcompletion.cc @@ -52,8 +52,31 @@ int qux; } /* namespace Test_NS */ +/* The important thing with class baz is that both the class and the + constructor must have a template argument, we need the symbol to look + like: + + baz<TYPE_1>::baz<TYPE_2>(int,....whatever...) + + It doesn't really matter if TYPE_1 and TYPE_2 are the same or different, + but we create them differently in this test as it makes debugging GDB + slightly easier. */ + +template<typename S> +struct baz +{ + template<typename T> + baz (int p1, T a) + { + s = 0; + } + + S s; +}; + int main () { + baz<int> obj (2.3, 0.1); // Anonymous struct with method. struct { int get() { return 5; } diff --git a/gdb/testsuite/gdb.cp/cpcompletion.exp b/gdb/testsuite/gdb.cp/cpcompletion.exp index 8c5c90b..5838a54 100644 --- a/gdb/testsuite/gdb.cp/cpcompletion.exp +++ b/gdb/testsuite/gdb.cp/cpcompletion.exp @@ -135,3 +135,5 @@ with_test_prefix "expression with namespace" { # Add a disambiguating character and we get a unique completion. test_gdb_complete_unique "p Test_NS::f" "p Test_NS::foo" } + +test_gdb_complete_unique "break baz(int" "break baz(int, double)" diff --git a/gdb/testsuite/gdb.rust/completion.exp b/gdb/testsuite/gdb.rust/completion.exp new file mode 100644 index 0000000..8876395 --- /dev/null +++ b/gdb/testsuite/gdb.rust/completion.exp @@ -0,0 +1,33 @@ +# Copyright (C) 2023 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 a completion case that was causing GDB to crash. + +load_lib rust-support.exp + +require allow_rust_tests + +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 "complete break pars" ".*" diff --git a/gdb/testsuite/gdb.rust/completion.rs b/gdb/testsuite/gdb.rust/completion.rs new file mode 100644 index 0000000..8396e3f --- /dev/null +++ b/gdb/testsuite/gdb.rust/completion.rs @@ -0,0 +1,19 @@ +// Copyright (C) 2023 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/>. + +fn main() { + let four: u8 = "4".parse().unwrap(); + println!("{}", four); // set breakpoint here +} diff --git a/gdb/utils.c b/gdb/utils.c index 0138c8e..8928295 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -2108,6 +2108,8 @@ strncmp_iw_with_mode (const char *string1, const char *string2, || language == language_rust || language == language_fortran); + gdb_assert (match_for_lcd == nullptr || match_for_lcd->empty ()); + while (1) { if (skip_spaces |