diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 52a9b5ff4..8210fbba5 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1420,12 +1420,21 @@ Layout::topological_sort () { m_top_cells = 0; m_top_down_list.clear (); - m_top_down_list.reserve (m_cells_size); + + // NOTE: we explicitly count the cells here and do not rely on "m_cell_size". + // Reason is that this is somewhat safer, specifically directly after take() when + // the cell list is already reduced, but the cell pointers are still containing the cell + // (issue #905) + size_t ncells = 0; + for (const_iterator c = begin (); c != end (); ++c) { + ++ncells; + } + m_top_down_list.reserve (ncells); std::vector num_parents (m_cell_ptrs.size (), 0); // while there are cells to treat .. - while (m_top_down_list.size () != m_cells_size) { + while (m_top_down_list.size () != ncells) { size_t n_top_down_cells = m_top_down_list.size (); diff --git a/src/db/unit_tests/dbLibrariesTests.cc b/src/db/unit_tests/dbLibrariesTests.cc index c59c25e03..c60cd6c4f 100644 --- a/src/db/unit_tests/dbLibrariesTests.cc +++ b/src/db/unit_tests/dbLibrariesTests.cc @@ -700,3 +700,54 @@ TEST(4) } } +namespace { + +class PCell1Declaration : + public db::PCellDeclaration +{ + void produce (const db::Layout & /*layout*/, const std::vector & /*layer_ids*/, const db::pcell_parameters_type & /*parameters*/, db::Cell & /*cell*/) const + { + // ... + } +}; + +class PCell2Declaration : + public db::PCellDeclaration +{ + void produce (const db::Layout & /*layout*/, const std::vector & /*layer_ids*/, const db::pcell_parameters_type & /*parameters*/, db::Cell &cell) const + { + // NOTE: this is the self-reference: we use the library which defines the PCell and create a proxy to itself + std::pair l = db::LibraryManager::instance ().lib_by_name ("__PCellLibrary"); + tl_assert (l.first); + db::Library *lib = db::LibraryManager::instance ().lib (l.second); + std::pair pcell_id = lib->layout ().pcell_by_name ("PCell1"); + tl_assert (pcell_id.first); + db::cell_index_type pcell_var = lib->layout ().get_pcell_variant_dict (pcell_id.second, std::map ()); + + db::cell_index_type lib_cell = cell.layout ()->get_lib_proxy (lib, pcell_var); + cell.insert (db::CellInstArray (lib_cell, db::Trans ())); + } +}; + +} + +// self-referencing libraries +TEST(5_issue905) +{ + std::unique_ptr lib; + lib.reset (new db::Library ()); + lib->set_name ("__PCellLibrary"); + lib->layout ().register_pcell ("PCell1", new PCell1Declaration ()); + lib->layout ().register_pcell ("PCell2", new PCell2Declaration ()); + db::LibraryManager::instance ().register_lib (lib.get ()); + + db::Layout ly; + std::pair pc = lib->layout ().pcell_by_name ("PCell2"); + tl_assert (pc.first); + + db::cell_index_type lib_cell = lib->layout ().get_pcell_variant_dict (pc.second, std::map ()); + ly.get_lib_proxy (lib.get (), lib_cell); + + db::LibraryManager::instance ().delete_lib (lib.release ()); + EXPECT (true); +}