diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 10aa711eef5..f7d8a35888b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2021-12-11 Bruno Larsen + + PR gdb/28480 + + Pushed by Joel Brobecker + * valops.c (struct_field_searcher::update_result): Improve + ambiguous member detection. + 2021-11-03 Luis Machado PR gdb/28355 diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 54cfd221abb..725f348db9f 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2021-12-11 Bruno Larsen + + PR gdb/28480 + + Pushed by Joel Brobecker + * gdb.cp/ambiguous.cc: Add code to permit ambiguous member testing. + * gdb.cp/ambiguous.exp: Add ambiguous member test. + 2021-10-22 Tom de Vries PR tui/28483 diff --git a/gdb/testsuite/gdb.cp/ambiguous.cc b/gdb/testsuite/gdb.cp/ambiguous.cc index a55686547f2..af2198dcfbc 100644 --- a/gdb/testsuite/gdb.cp/ambiguous.cc +++ b/gdb/testsuite/gdb.cp/ambiguous.cc @@ -1,3 +1,4 @@ +class empty { }; class A1 { public: @@ -17,6 +18,17 @@ public: int y; }; +#if !defined (__GNUC__) || __GNUC__ > 7 +# define NO_UNIQUE_ADDRESS [[no_unique_address]] +#else +# define NO_UNIQUE_ADDRESS +#endif + +class A4 { +public: + NO_UNIQUE_ADDRESS empty x; +}; + class X : public A1, public A2 { public: int z; @@ -77,6 +89,10 @@ public: int jva1v; }; +class JE : public A1, public A4 { +public: +}; + int main() { A1 a1; @@ -92,6 +108,7 @@ int main() JVA1 jva1; JVA2 jva2; JVA1V jva1v; + JE je; int i; @@ -173,5 +190,7 @@ int main() jva1v.i = 4; jva1v.jva1v = 5; + je.A1::x = 1; + return 0; /* set breakpoint here */ } diff --git a/gdb/testsuite/gdb.cp/ambiguous.exp b/gdb/testsuite/gdb.cp/ambiguous.exp index 008898c5818..1e63dc0c5dc 100644 --- a/gdb/testsuite/gdb.cp/ambiguous.exp +++ b/gdb/testsuite/gdb.cp/ambiguous.exp @@ -264,3 +264,13 @@ gdb_test "print (A1)(KV)jva1" " = \{x = 3, y = 4\}" # JVA1V is derived from A1; A1 is a virtual base indirectly # and also directly; must not report ambiguity when a JVA1V is cast to an A1. gdb_test "print (A1)jva1v" " = {x = 1, y = 2}" + +# C++20 introduced a way to have ambiguous fields with the same byte offset. +# This class explicitly tests for that. +# if this is tested with a compiler that can't handle [[no_unique_address]] +# the code should still correctly identify the ambiguity because of +# different byte offsets. +test_ambiguous "je.x" "x" "JE" { + "'int A1::x' (JE -> A1)" + "'empty A4::x' (JE -> A4)" +} diff --git a/gdb/valops.c b/gdb/valops.c index bd547923496..3769ab9630a 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -1969,6 +1969,34 @@ struct_field_searcher::update_result (struct value *v, LONGEST boffset) space. */ if (m_fields.empty () || m_last_boffset != boffset) m_fields.push_back ({m_struct_path, v}); + else + { + /*Fields can occupy the same space and have the same name (be + ambiguous). This can happen when fields in two different base + classes are marked [[no_unique_address]] and have the same name. + The C++ standard says that such fields can only occupy the same + space if they are of different type, but we don't rely on that in + the following code. */ + bool ambiguous = false, insert = true; + for (const found_field &field: m_fields) + { + if(field.path.back () != m_struct_path.back ()) + { + /* Same boffset points to members of different classes. + We have found an ambiguity and should record it. */ + ambiguous = true; + } + else + { + /* We don't need to insert this value again, because a + non-ambiguous path already leads to it. */ + insert = false; + break; + } + } + if (ambiguous && insert) + m_fields.push_back ({m_struct_path, v}); + } } } }