Rust's pointer comparison don't compare the pointers, but the pointed-to values. This is the case for &T, &mut T, Box<T>, Rc<T>, Arc<T>, etc., all but the raw pointers *const T and *mut T themselves. Those smart pointers usually have an extra method (std::rc::Rc::ptr_eq in this case) for actual pointer comparison.
This is similar to how Debug on those pointers prints the pointed-to value rather than the address, and you need the Pointer trait to print the actual address: Rust isn't very address-focused.
Now, if you have a type such as f64 which doesn't have a transitive == (that is, it implements PartialEq but not Eq) and wrap it in an Rc, you also get non-transitivity:
fn main() {
let a = std::rc::Rc::new(std::f64::NAN);
println!("a == a?: {}", a == a);
println!(
"a == a but with pointer comparison?: {}",
std::rc::Rc::ptr_eq(&a, &a)
);
// But:
let answer = std::rc::Rc::new(42);
// surely this will have a different address
let another_answer = std::rc::Rc::new(42);
println!("answer == another_answer?: {}", answer == another_answer);
}
prints:
a == a?: false
a == a but with pointer comparison?: true
answer == another_answer?: true
If T happens to implement Eq as well as PartialEq, the current implementation indeed does a pointer comparison, using the yet-to-be-stabilized specialization feature.
See also: