aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/completer.h19
-rw-r--r--gdb/cp-support.c7
-rw-r--r--gdb/testsuite/gdb.cp/cpcompletion.cc23
-rw-r--r--gdb/testsuite/gdb.cp/cpcompletion.exp2
-rw-r--r--gdb/testsuite/gdb.rust/completion.exp33
-rw-r--r--gdb/testsuite/gdb.rust/completion.rs19
-rw-r--r--gdb/utils.c2
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