Skip to content

Commit c8e2bf9

Browse files
committed
add essay
1 parent 2a7ba97 commit c8e2bf9

File tree

1 file changed

+56
-87
lines changed

1 file changed

+56
-87
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

Lines changed: 56 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,53 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
190190
"ptr_type={ptr_type}, pointee_type={pointee_type}",
191191
);
192192

193+
/*
194+
This block differentiates between mutable/immutable AND ref/ptr.
195+
196+
References to references (&&T) are invalid constructs in C/C++, and we are piggybacking off
197+
of their type system when using LLDB (`TypeSystemClang`). Ptr-to-ref (*&T) and ref-to-ptr (&*T)
198+
are valid constructs though. That means we can tell the debugger that ref-to-ref's are actually
199+
ref-to-ptr's.
200+
201+
Additionally, to help debugger visualizers differentiate ref-to-ref's that *look like* ref-to-ptr
202+
and *actual* ref-to-ptr, we can use the `rvalue_reference` tag. It's a C++ feature that doesn't
203+
quite have an equivalent in Rust, but *is* represented as `&&` which is perfect! That means
204+
ref-to-refs (&&T) will look like `T *&&` (i.e. an rvalue_reference to a pointer to T)
205+
and on the debugger visualizer end, the scripts can "undo" that translation.
206+
207+
To handle immutable vs mutable (&/&mut) we use the `const` modifier. The modifier is applied
208+
with proper C/C++ rules (i.e. pointer-to-constant vs constant pointer). This means that an
209+
immutable reference applies the const modifier to the *pointee type*. When reversing the
210+
debuginfo translation, the `const` modifier doesn't describe the value it's applied to, it describes
211+
the pointer to the value. This is a **very** important distinction.
212+
213+
Here are some examples, the Rust representation is on the left and the debuginfo translation on
214+
the right
215+
216+
Cosnt vs Mut:
217+
*const T -> const T *
218+
*mut T -> T *
219+
220+
*const *const T -> const T *const *
221+
*mut *mut T -> T **
222+
223+
*mut *const T -> const T **
224+
*const *mut T -> T *const *
225+
226+
Nested References:
227+
&T -> const T &
228+
&&T -> const T *const &&
229+
&&&T -> const T &const *const &&
230+
&&&&T -> const T *const &&const *const &&
231+
232+
&mut T -> T &
233+
&mut &mut T -> T *&&
234+
&mut &mut &mut T -> T &*&&
235+
&mut &mut &mut &mut T -> T *&&*&&
236+
*/
193237
let di_node = match (ptr_type.kind(), pointee_type.kind()) {
238+
// if we have a ref-to-ref, convert the inner ref to a ptr and the outter ref to an rvalue ref
239+
// and apply `const` to the inner ref's value and the inner ref itself as necessary
194240
(ty::Ref(_, _, ptr_mut), ty::Ref(_, inner_type, ptee_mut)) => unsafe {
195241
let inner_type_di_node = type_di_node(cx, *inner_type);
196242
let inner_type_di_node = if ptee_mut.is_not() {
@@ -203,28 +249,31 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
203249
inner_type_di_node
204250
};
205251

206-
let ptr_wrapper = llvm::LLVMRustDIBuilderCreateReferenceType(
252+
// creating a reference node with the pointer tag outputs a regular pointer as far as LLDB
253+
// is concerned
254+
let wrapped_ref = llvm::LLVMRustDIBuilderCreateReferenceType(
207255
DIB(cx),
208256
DW_TAG_pointer_type,
209257
inner_type_di_node,
210258
);
211259

212-
let ptr_wrapper = if ptr_mut.is_not() {
260+
let wrapped_ref = if ptr_mut.is_not() {
213261
llvm::LLVMRustDIBuilderCreateQualifiedType(
214262
DIB(cx),
215263
DW_TAG_const_type,
216-
ptr_wrapper,
264+
wrapped_ref,
217265
)
218266
} else {
219-
ptr_wrapper
267+
wrapped_ref
220268
};
221269

222270
llvm::LLVMRustDIBuilderCreateReferenceType(
223271
DIB(cx),
224272
DW_TAG_rvalue_reference_type,
225-
ptr_wrapper,
273+
wrapped_ref,
226274
)
227275
},
276+
// if we have a ref-to-<not a ref>, apply `const` to the inner value as necessary
228277
(ty::Ref(_, _, ptr_mut), _) => unsafe {
229278
let pointee_type_di_node = if ptr_mut.is_not() {
230279
llvm::LLVMRustDIBuilderCreateQualifiedType(
@@ -242,6 +291,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
242291
pointee_type_di_node,
243292
)
244293
},
294+
// if we have any pointer, apply `const` to the inner value as necessary
245295
(ty::RawPtr(_, ptr_mut), _) => unsafe {
246296
let pointee_type_di_node = if ptr_mut.is_not() {
247297
llvm::LLVMRustDIBuilderCreateQualifiedType(
@@ -263,6 +313,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
263313
ptr_type_debuginfo_name.len(),
264314
)
265315
},
316+
// apply no translations to `Box`
266317
(ty::Adt(_, _), _) => unsafe {
267318
llvm::LLVMRustDIBuilderCreatePointerType(
268319
DIB(cx),
@@ -277,88 +328,6 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
277328
_ => todo!(),
278329
};
279330

280-
// Immutable pointers/references will mark the data as `const`. For example:
281-
// unsigned char & => &mut u8
282-
// const unsigned char & => &u8
283-
// unsigned char * => *mut u8
284-
// const unsigned char * => *const u8
285-
// let di_node = match ptr_type.kind() {
286-
// ty::Ref(_, _, mutability) => unsafe {
287-
// let pointee_type_di_node = if mutability.is_not() {
288-
// llvm::LLVMRustDIBuilderCreateQualifiedType(
289-
// DIB(cx),
290-
// DW_TAG_const_type,
291-
// pointee_type_di_node,
292-
// )
293-
// } else {
294-
// pointee_type_di_node
295-
// };
296-
297-
// if let ty::Ref(_, pt_e, _) = pointee_type.kind() {
298-
// let pointee_type_di_node = type_di_node(cx, *pt_e);
299-
// let temp = llvm::LLVMRustDIBuilderCreateReferenceType(
300-
// DIB(cx),
301-
// 0xf,
302-
// pointee_type_di_node,
303-
// );
304-
305-
// let temp = if mutability.is_not() {
306-
// llvm::LLVMRustDIBuilderCreateQualifiedType(
307-
// DIB(cx),
308-
// DW_TAG_const_type,
309-
// temp,
310-
// )
311-
// } else {
312-
// temp
313-
// };
314-
315-
// llvm::LLVMRustDIBuilderCreateReferenceType(
316-
// DIB(cx),
317-
// DW_TAG_rvalue_reference_type,
318-
// temp,
319-
// )
320-
// } else {
321-
// llvm::LLVMRustDIBuilderCreateReferenceType(
322-
// DIB(cx),
323-
// DW_TAG_reference_type,
324-
// pointee_type_di_node,
325-
// )
326-
// }
327-
// },
328-
// ty::RawPtr(_, mutability) => unsafe {
329-
// let pointee_type_di_node = if mutability.is_not() {
330-
// llvm::LLVMRustDIBuilderCreateQualifiedType(
331-
// DIB(cx),
332-
// DW_TAG_const_type,
333-
// pointee_type_di_node,
334-
// )
335-
// } else {
336-
// pointee_type_di_node
337-
// };
338-
// llvm::LLVMRustDIBuilderCreatePointerType(
339-
// DIB(cx),
340-
// pointee_type_di_node,
341-
// data_layout.pointer_size.bits(),
342-
// data_layout.pointer_align.abi.bits() as u32,
343-
// 0, // Ignore DWARF address space.
344-
// ptr_type_debuginfo_name.as_c_char_ptr(),
345-
// ptr_type_debuginfo_name.len(),
346-
// )
347-
// },
348-
// ty::Adt(_, _) => unsafe {
349-
// llvm::LLVMRustDIBuilderCreatePointerType(
350-
// DIB(cx),
351-
// pointee_type_di_node,
352-
// data_layout.pointer_size.bits(),
353-
// data_layout.pointer_align.abi.bits() as u32,
354-
// 0, // Ignore DWARF address space.
355-
// ptr_type_debuginfo_name.as_c_char_ptr(),
356-
// ptr_type_debuginfo_name.len(),
357-
// )
358-
// },
359-
// _ => unreachable!("Thin pointer not of type ty::RawPtr, ty::Ref, or ty::Adt"),
360-
// };
361-
362331
DINodeCreationResult { di_node, already_stored_in_typemap: false }
363332
}
364333
Some(wide_pointer_kind) => {

0 commit comments

Comments
 (0)