diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index 5da01b96fa5e3..33b99d26e808a 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -333,27 +333,34 @@ def children(self): # Yield each key (and optionally value) from a BoxedNode. def children_of_node(boxed_node, height, want_values): node_ptr = boxed_node['ptr']['pointer'] - if height > 0: - type_name = str(node_ptr.type.target()).replace('LeafNode', 'InternalNode') - node_type = gdb.lookup_type(type_name) - node_ptr = node_ptr.cast(node_type.pointer()) - leaf = node_ptr['data'] - else: - leaf = node_ptr.dereference() - keys = leaf['keys'] - if want_values: - values = leaf['vals'] - length = int(leaf['len']) - for i in xrange(0, length + 1): + head = node_ptr.dereference() + length = int(head['len']) + if length > 0: if height > 0: - child_ptr = node_ptr['edges'][i]['value']['value'] - for child in children_of_node(child_ptr, height - 1, want_values): - yield child - if i < length: - if want_values: - yield (keys[i]['value']['value'], values[i]['value']['value']) - else: - yield keys[i]['value']['value'] + type_name = str(node_ptr.type.target()).replace('NodeHeader', 'InternalNode', 1) + node_type = gdb.lookup_type(type_name) + node_ptr = node_ptr.cast(node_type.pointer()) + leaf = node_ptr['data'] + edges = node_ptr['edges'] + else: + type_name = str(node_ptr.type.target()).replace('NodeHeader', 'LeafNode', 1) + node_type = gdb.lookup_type(type_name) + node_ptr = node_ptr.cast(node_type.pointer()) + leaf = node_ptr.dereference() + edges = None + keys = leaf['keys'] + if want_values: + values = leaf['vals'] + for i in xrange(0, length + 1): + if edges: + child_ptr = edges[i]['value']['value'] + for child in children_of_node(child_ptr, height - 1, want_values): + yield child + if i < length: + if want_values: + yield (keys[i]['value']['value'], values[i]['value']['value']) + else: + yield keys[i]['value']['value'] class RustStdBTreeSetPrinter(object): def __init__(self, val): diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index d9cdebb4f7354..563392eda2bbe 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -152,30 +152,34 @@ impl InternalNode { } } -/// An owned pointer to a node. This basically is either `Box>` or -/// `Box>`. However, it contains no information as to which of the two types -/// of nodes is actually behind the box, and, partially due to this lack of information, has no -/// destructor. +/// A managed, non-null pointer to a node. This is either an owned pointer to +/// `LeafNode`, an owned pointer to `InternalNode`, or a (not owned) +/// pointer to `NodeHeader<(), ()` (more specifically, the pointer to EMPTY_ROOT_NODE). +/// All of these types have a `NodeHeader` prefix, meaning that they have at +/// least the same size as `NodeHeader` and store the same kinds of data at the same +/// offsets; and they have a pointer alignment at least as large as `NodeHeader`'s. +/// So that's the pointee type we store, and `as_header()` is unconditionally safe. +/// However, `BoxedNode` contains no information as to which of the three types +/// of nodes it actually contains, and, partially due to this lack of information, +/// has no destructor. struct BoxedNode { - ptr: Unique>, + ptr: Unique>, } impl BoxedNode { fn from_leaf(node: Box>) -> Self { - BoxedNode { ptr: Box::into_unique(node) } + BoxedNode { ptr: Box::into_unique(node).cast() } } fn from_internal(node: Box>) -> Self { - unsafe { - BoxedNode { ptr: Unique::new_unchecked(Box::into_raw(node) as *mut LeafNode) } - } + BoxedNode { ptr: Box::into_unique(node).cast() } } - unsafe fn from_ptr(ptr: NonNull>) -> Self { + unsafe fn from_ptr(ptr: NonNull>) -> Self { BoxedNode { ptr: Unique::from(ptr) } } - fn as_ptr(&self) -> NonNull> { + fn as_ptr(&self) -> NonNull> { NonNull::from(self.ptr) } } @@ -197,11 +201,7 @@ impl Root { pub fn shared_empty_root() -> Self { Root { - node: unsafe { - BoxedNode::from_ptr(NonNull::new_unchecked( - &EMPTY_ROOT_NODE as *const _ as *const LeafNode as *mut _, - )) - }, + node: unsafe { BoxedNode::from_ptr(NonNull::from(&EMPTY_ROOT_NODE).cast()) }, height: 0, } } @@ -310,7 +310,7 @@ impl Root { /// Turning this into a `NodeHeader` reference is always safe. pub struct NodeRef { height: usize, - node: NonNull>, + node: NonNull>, // `root` is null unless the borrow type is `Mut` root: *const Root, _marker: PhantomData<(BorrowType, Type)>, @@ -372,11 +372,11 @@ impl NodeRef { /// See `NodeRef` on why the node may not be a shared root. unsafe fn as_leaf(&self) -> &LeafNode { debug_assert!(!self.is_shared_root()); - self.node.as_ref() + &*(self.node.as_ptr() as *const LeafNode) } fn as_header(&self) -> &NodeHeader { - unsafe { &*(self.node.as_ptr() as *const NodeHeader) } + unsafe { self.node.as_ref() } } /// Returns whether the node is the shared, empty root. @@ -505,7 +505,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// This also implies you can invoke this member on the shared root, but the resulting pointer /// might not be properly aligned and definitely would not allow accessing keys and values. fn as_leaf_mut(&mut self) -> *mut LeafNode { - self.node.as_ptr() + self.node.as_ptr() as *mut LeafNode } /// The caller must ensure that the node is not the shared root. diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs index f8997fad9a53f..7ed23de480781 100644 --- a/src/test/debuginfo/pretty-std-collections.rs +++ b/src/test/debuginfo/pretty-std-collections.rs @@ -20,20 +20,26 @@ // gdb-command: print btree_map // gdb-check:$2 = BTreeMap(len: 15) = {[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5, [6] = 6, [7] = 7, [8] = 8, [9] = 9, [10] = 10, [11] = 11, [12] = 12, [13] = 13, [14] = 14} +// gdb-command: print empty_btree_map +// gdb-check:$3 = BTreeMap<(), ()>(len: 0) + +// gdb-command: print nasty_btree_map +// gdb-check:$4 = BTreeMap(len: 1) = {[1] = pretty_std_collections::MyNodeHeader (11)} + // gdb-command: print vec_deque -// gdb-check:$3 = VecDeque(len: 3, cap: 8) = {5, 3, 7} +// gdb-check:$5 = VecDeque(len: 3, cap: 8) = {5, 3, 7} // gdb-command: print vec_deque2 -// gdb-check:$4 = VecDeque(len: 7, cap: 8) = {2, 3, 4, 5, 6, 7, 8} +// gdb-check:$6 = VecDeque(len: 7, cap: 8) = {2, 3, 4, 5, 6, 7, 8} #![allow(unused_variables)] -use std::collections::BTreeSet; use std::collections::BTreeMap; +use std::collections::BTreeSet; use std::collections::VecDeque; +struct MyNodeHeader(i32); // helps to ensure we don't blindly replace substring "NodeHeader" fn main() { - // BTreeSet let mut btree_set = BTreeSet::new(); for i in 0..15 { @@ -45,6 +51,9 @@ fn main() { for i in 0..15 { btree_map.insert(i, i); } + let empty_btree_map: BTreeMap<(), ()> = BTreeMap::new(); + let mut nasty_btree_map: BTreeMap = BTreeMap::new(); + nasty_btree_map.insert(1, MyNodeHeader(11)); // VecDeque let mut vec_deque = VecDeque::new(); @@ -63,4 +72,6 @@ fn main() { zzz(); // #break } -fn zzz() { () } +fn zzz() { + () +}