Skip to content

Commit 2337f88

Browse files
committed
add essay
1 parent 61c857c commit 2337f88

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
@@ -189,7 +189,53 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
189189
"ptr_type={ptr_type}, pointee_type={pointee_type}",
190190
);
191191

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

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

211-
let ptr_wrapper = if ptr_mut.is_not() {
259+
let wrapped_ref = if ptr_mut.is_not() {
212260
llvm::LLVMRustDIBuilderCreateQualifiedType(
213261
DIB(cx),
214262
DW_TAG_const_type,
215-
ptr_wrapper,
263+
wrapped_ref,
216264
)
217265
} else {
218-
ptr_wrapper
266+
wrapped_ref
219267
};
220268

221269
llvm::LLVMRustDIBuilderCreateReferenceType(
222270
DIB(cx),
223271
DW_TAG_rvalue_reference_type,
224-
ptr_wrapper,
272+
wrapped_ref,
225273
)
226274
},
275+
// if we have a ref-to-<not a ref>, apply `const` to the inner value as necessary
227276
(ty::Ref(_, _, ptr_mut), _) => unsafe {
228277
let pointee_type_di_node = if ptr_mut.is_not() {
229278
llvm::LLVMRustDIBuilderCreateQualifiedType(
@@ -241,6 +290,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
241290
pointee_type_di_node,
242291
)
243292
},
293+
// if we have any pointer, apply `const` to the inner value as necessary
244294
(ty::RawPtr(_, ptr_mut), _) => unsafe {
245295
let pointee_type_di_node = if ptr_mut.is_not() {
246296
llvm::LLVMRustDIBuilderCreateQualifiedType(
@@ -262,6 +312,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
262312
ptr_type_debuginfo_name.len(),
263313
)
264314
},
315+
// apply no translations to `Box`
265316
(ty::Adt(_, _), _) => unsafe {
266317
llvm::LLVMRustDIBuilderCreatePointerType(
267318
DIB(cx),
@@ -276,88 +327,6 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
276327
_ => todo!(),
277328
};
278329

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

0 commit comments

Comments
 (0)