Initial `bindings/reference/pointers_and_references.md`.

PiperOrigin-RevId: 537135298
diff --git a/docs/bindings/reference/pointers_and_references.md b/docs/bindings/reference/pointers_and_references.md
new file mode 100644
index 0000000..f80f6e3
--- /dev/null
+++ b/docs/bindings/reference/pointers_and_references.md
@@ -0,0 +1,133 @@
+# Bindings for pointer and reference types
+
+Here we describe how Crubit maps pointer and reference types.
+
+## Rust bindings for C++ APIs
+
+Rust bindings for lifetime-annotated C++ pointers and references look as
+follows:
+
+<!-- The examples in the table below are based on
+`FunctionTakingPointersAndReferences` from
+`rs_bindings_from_cc/test/golden/types_rs_api.rs`.  Note that
+`FieldTypeTestStruct` can't be used because its fields are not
+lifetime-annotated (lifetime elision doesn't work with structs). -->
+
+C++ API       | Rust bindings
+------------- | -------------------
+`const T& $a` | `&'a T`
+`T& $a`       | `&'a mut T`
+`const T* $a` | `Option<&'a T>`
+`T* $a`       | `Option<&'a mut T>`
+
+TODO: Document how explicit lifetime annotations work. (A prerequisite might be
+defining `$a` macros via a new header under `crubit/support`.)
+
+TODO: Document how `#pragma clang lifetime_elision` works.
+
+C++ pointers and references that are *not* annotated with lifetimes look as
+follows:
+
+C++ API    | Rust bindings
+---------- | -------------
+`const T&` | `*const T`
+`T&`       | `*mut T`
+`const T*` | `*const T`
+`T*`       | `*mut T`
+
+TODO: Document what happens for `void*`.
+
+## C++ bindings for Rust APIs
+
+Rust bindings for lifetime-annotated C++ pointers and references look as
+follows:
+
+Rust API   | C++ bindings
+---------- | -------------------------------------
+`*const T` | `const T*`
+`*mut T`   | `T*`
+`&T`       | TODO(b/258235219): Not supported yet.
+`&mut T`   | TODO(b/258235219): Not supported yet.
+`&str`     | TODO(b/262580415): Not supported yet.
+`&mut str` | TODO(b/262580415): Not supported yet.
+`&[T]`     | TODO(b/271016831): Not supported yet.
+`&mut[T]`  | TODO(b/271016831): Not supported yet.
+
+## Safety notes
+
+Rust reference
+[documents Undefined Behavior (UB)](https://doc.rust-lang.org/reference/behavior-considered-undefined.html)
+and says that "it is the programmer's responsibility when writing unsafe code to
+ensure that any safe code interacting with the unsafe code cannot trigger these
+[undefined] behaviors". A programmer using Crubit bindings has the same
+responsibility: Crubit is implicitly "unsafe", and incorrect usage can cause UB.
+The sections below document requirements for safely using Crubit when working
+with Rust and C++ references and pointers. The requirements are the same as the
+ones
+[documented in the Rust reference](https://doc.rust-lang.org/reference/behavior-considered-undefined.html),
+but are rephrased below from Crubit perspective.
+
+The safety requirements below focus on avoiding UB related to Rust references
+and therefore matter in scenarios where Crubit-generated code may create Rust
+references out of C++ references or C++ pointers:
+
+-   Today: Using Crubit-generated Rust bindings for C++ APIs if the bindings
+    accept, store, or return Rust references. TODO: In the future Crubit should
+    use `CppRef<T>` in the generated bindings (and this should mitigate some of
+    the memory safety concerns).
+-   In the future: Using Crubit-generated C++ bindings for Rust APIs if the
+    bindings wrap Rust APIs that accept, store, or return Rust references.
+    TODO(b/258235219): Add support for C++ bindings for Rust APIs using `&T`.
+
+### Incorrect C++ lifetime annotations
+
+Incorrect lifetime annotations may lead to UB. Rust's borrow checker prevents
+incorrect lifetime annotations, but lifetime annotations of C++ APIs are not
+verified by the C++ compiler and Crubit's optional lifetime analysis can't
+detect all incorrect annotations. Note that Crubit assumes that lifetime
+annotations are correct both for explicit annotations (e.g. `int& $a f2(int&
+$a);`) as well as for annotations provided by `#pragma clang lifetime_elision`.
+
+### C++ mutating values referenced by Rust
+
+Mutating a value in C++ may lead to UB if the mutation happens while Rust holds
+a references to that value. This applies to Rust shared references (e.g. `&T`)
+and to exclusive references (e.g. `&mut T`).
+
+TODO(b/258249993): After `cc_bindings_from_rs` generates assignment operators,
+explicitly document them here as an example.
+
+TODO(b/271002281): After `cc_bindings_from_rs` exposes public fields, explicitly
+document them here as an example.
+
+TODO: Try to succintly mention the idea that short-lived / non-retained
+references are safe from the mutation risk.
+
+### Dangling or null references
+
+All references and
+[`NonNull` pointers](https://doc.rust-lang.org/std/ptr/struct.NonNull.html) must
+not be null, and if they point to a nonzero span of memory, must not be
+dangling. (The behavior of a program which violates these rules is undefined.)
+
+C++ doesn't share these rules, and care must be taken when converting Rust
+references to and from C++ pointers. For example, spans/slices are particularly
+error-prone: a Rust empty slice uses a dangling pointer (which is UB in C++),
+and a C++ empty span (often) uses nullptr (which is UB in Rust). To effectively
+use spans in FFI, one must either use non-native types, or perform a conversion
+operation which rewrites the pointer values. For that, we recommend using the
+conversion routines provided by Crubit support library (e.g. `impl
+From<string_view> for &[u8]`).
+
+TODO(b/271016831, b/262580415): Cover `rs_std::Slice<T>` and/or `rs_std::str`
+above once these types are provided by Crubit.
+
+### Breaking Rust aliasing rules
+
+Constructing a Rust references that aliases the same address as an already
+existing exclusive reference `&mut T` may lead to UB.
+
+TODO: Provide FFI-related examples.
+
+TODO: Document what runtime checks are provided by Crubit (and link to a
+separate md document that explains why general checks are infeasible).
diff --git a/rs_bindings_from_cc/test/golden/types.h b/rs_bindings_from_cc/test/golden/types.h
index 81e314f..c81b37c 100644
--- a/rs_bindings_from_cc/test/golden/types.h
+++ b/rs_bindings_from_cc/test/golden/types.h
@@ -64,6 +64,11 @@
   ForwardDeclaredStruct* forward_declared_ptr_field;
 };
 
+void FunctionTakingPointersAndReferences(const int& const_ref_param,
+                                         int& mut_ref_param,
+                                         const int* const_ptr_param,
+                                         int* mut_ptr_param);
+
 inline void VoidReturningFunction() {}
 
 // Note especially the use of references. If we convert those to pointers,
diff --git a/rs_bindings_from_cc/test/golden/types_rs_api.rs b/rs_bindings_from_cc/test/golden/types_rs_api.rs
index 1f9839d..60266ab 100644
--- a/rs_bindings_from_cc/test/golden/types_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/types_rs_api.rs
@@ -138,6 +138,23 @@
 }
 
 #[inline(always)]
+pub fn FunctionTakingPointersAndReferences<'a, 'b, 'c, 'd>(
+    const_ref_param: &'a ::core::ffi::c_int,
+    mut_ref_param: &'b mut ::core::ffi::c_int,
+    const_ptr_param: Option<&'c ::core::ffi::c_int>,
+    mut_ptr_param: Option<&'d mut ::core::ffi::c_int>,
+) {
+    unsafe {
+        crate::detail::__rust_thunk___Z35FunctionTakingPointersAndReferencesRKiRiPS_Pi(
+            const_ref_param,
+            mut_ref_param,
+            const_ptr_param,
+            mut_ptr_param,
+        )
+    }
+}
+
+#[inline(always)]
 pub fn VoidReturningFunction() {
     unsafe { crate::detail::__rust_thunk___Z21VoidReturningFunctionv() }
 }
@@ -186,6 +203,18 @@
             __this: &'a mut ::core::mem::MaybeUninit<crate::FieldTypeTestStruct>,
             __param_0: ::ctor::RvalueReference<'b, crate::FieldTypeTestStruct>,
         );
+        #[link_name = "_Z35FunctionTakingPointersAndReferencesRKiRiPS_Pi"]
+        pub(crate) fn __rust_thunk___Z35FunctionTakingPointersAndReferencesRKiRiPS_Pi<
+            'a,
+            'b,
+            'c,
+            'd,
+        >(
+            const_ref_param: &'a ::core::ffi::c_int,
+            mut_ref_param: &'b mut ::core::ffi::c_int,
+            const_ptr_param: Option<&'c ::core::ffi::c_int>,
+            mut_ptr_param: Option<&'d mut ::core::ffi::c_int>,
+        );
         pub(crate) fn __rust_thunk___Z21VoidReturningFunctionv();
         pub(crate) fn __rust_thunk___Z32FunctionPointerReturningFunctionv() -> Option<
             extern "C" fn(