diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 01af964a83e26..a793fc2aa2e55 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -6,6 +6,13 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+mod variance;
+
+#[unstable(feature = "phantom_variance_markers", issue = "135806")]
+pub use self::variance::{
+    PhantomContravariant, PhantomContravariantLifetime, PhantomCovariant, PhantomCovariantLifetime,
+    PhantomInvariant, PhantomInvariantLifetime, Variance, variance,
+};
 use crate::cell::UnsafeCell;
 use crate::cmp;
 use crate::fmt::Debug;
diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs
new file mode 100644
index 0000000000000..23334e6575ddf
--- /dev/null
+++ b/library/core/src/marker/variance.rs
@@ -0,0 +1,260 @@
+#![unstable(feature = "phantom_variance_markers", issue = "135806")]
+
+use super::PhantomData;
+use crate::any::type_name;
+use crate::cmp::Ordering;
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+
+macro_rules! first_token {
+    ($first:tt $($rest:tt)*) => {
+        $first
+    };
+}
+
+macro_rules! phantom_type {
+    ($(
+        $(#[$attr:meta])*
+        pub struct $name:ident <$t:ident> ($($inner:tt)*);
+    )*) => {$(
+        $(#[$attr])*
+        pub struct $name<$t>($($inner)*) where T: ?Sized;
+
+        impl<T> $name<T>
+            where T: ?Sized
+        {
+            /// Constructs a new instance of the variance marker.
+            pub const fn new() -> Self {
+                Self(PhantomData)
+            }
+        }
+
+        impl<T> self::sealed::Sealed for $name<T> where T: ?Sized {
+            const VALUE: Self = Self::new();
+        }
+        impl<T> Variance for $name<T> where T: ?Sized {}
+
+        impl<T> Default for $name<T>
+            where T: ?Sized
+        {
+            fn default() -> Self {
+                Self(PhantomData)
+            }
+        }
+
+        impl<T> fmt::Debug for $name<T>
+            where T: ?Sized
+        {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}<{}>", stringify!($name), type_name::<T>())
+            }
+        }
+
+        impl<T> Clone for $name<T>
+            where T: ?Sized
+        {
+            fn clone(&self) -> Self {
+                *self
+            }
+        }
+
+        impl<T> Copy for $name<T> where T: ?Sized {}
+
+        impl<T> PartialEq for $name<T>
+            where T: ?Sized
+        {
+            fn eq(&self, _: &Self) -> bool {
+                true
+            }
+        }
+
+        impl<T> Eq for $name<T> where T: ?Sized {}
+
+        impl<T> PartialOrd for $name<T>
+            where T: ?Sized
+        {
+            fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
+                Some(Ordering::Equal)
+            }
+        }
+
+        impl<T> Ord for $name<T>
+            where T: ?Sized
+        {
+            fn cmp(&self, _: &Self) -> Ordering {
+                Ordering::Equal
+            }
+        }
+
+        impl<T> Hash for $name<T>
+            where T: ?Sized
+        {
+            fn hash<H: Hasher>(&self, _: &mut H) {}
+        }
+    )*};
+}
+
+macro_rules! phantom_lifetime {
+    ($(
+        $(#[$attr:meta])*
+        pub struct $name:ident <$lt:lifetime> ($($inner:tt)*);
+    )*) => {$(
+        $(#[$attr])*
+        #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+        pub struct $name<$lt>($($inner)*);
+
+        impl $name<'_> {
+            /// Constructs a new instance of the variance marker.
+            pub const fn new() -> Self {
+                Self(first_token!($($inner)*)(PhantomData))
+            }
+        }
+
+        impl self::sealed::Sealed for $name<'_> {
+            const VALUE: Self = Self::new();
+        }
+        impl Variance for $name<'_> {}
+
+        impl fmt::Debug for $name<'_> {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}", stringify!($name))
+            }
+        }
+    )*};
+}
+
+phantom_lifetime! {
+    /// Zero-sized type used to mark a lifetime as covariant.
+    ///
+    /// Covariant lifetimes must live at least as long as declared. See [the reference][1] for more
+    /// information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomCovariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomCovariantLifetime<'a>>() == 1`
+    pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>);
+    /// Zero-sized type used to mark a lifetime as contravariant.
+    ///
+    /// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for
+    /// more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomContravariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomContravariantLifetime<'a>>() == 1`
+    pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>);
+    /// Zero-sized type used to mark a lifetime as invariant.
+    ///
+    /// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer.
+    /// See [the reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomInvariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomInvariantLifetime<'a>>() == 1`
+    pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>);
+}
+
+phantom_type! {
+    /// Zero-sized type used to mark a type parameter as covariant.
+    ///
+    /// Types used as part of the return value from a function are covariant. If the type is _also_
+    /// passed as a parameter then it is [invariant][PhantomInvariant]. See [the reference][1] for
+    /// more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomCovariant<T>>() == 0`
+    /// * `align_of::<PhantomCovariant<T>>() == 1`
+    pub struct PhantomCovariant<T>(PhantomData<fn() -> T>);
+    /// Zero-sized type used to mark a type parameter as contravariant.
+    ///
+    /// Types passed as arguments to a function are contravariant. If the type is _also_ part of the
+    /// return value from a function then it is [invariant][PhantomInvariant]. See [the
+    /// reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomContravariant<T>>() == 0`
+    /// * `align_of::<PhantomContravariant<T>>() == 1`
+    pub struct PhantomContravariant<T>(PhantomData<fn(T)>);
+    /// Zero-sized type used to mark a type parameter as invariant.
+    ///
+    /// Types that are both passed as an argument _and_ used as part of the return value from a
+    /// function are invariant. See [the reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomInvariant<T>>() == 0`
+    /// * `align_of::<PhantomInvariant<T>>() == 1`
+    pub struct PhantomInvariant<T>(PhantomData<fn(T) -> T>);
+}
+
+mod sealed {
+    pub trait Sealed {
+        const VALUE: Self;
+    }
+}
+
+/// A marker trait for phantom variance types.
+pub trait Variance: sealed::Sealed + Default {}
+
+/// Construct a variance marker; equivalent to [`Default::default`].
+///
+/// This type can be any of the following. You generally should not need to explicitly name the
+/// type, however.
+///
+/// - [`PhantomCovariant`]
+/// - [`PhantomContravariant`]
+/// - [`PhantomInvariant`]
+/// - [`PhantomCovariantLifetime`]
+/// - [`PhantomContravariantLifetime`]
+/// - [`PhantomInvariantLifetime`]
+///
+/// # Example
+///
+/// ```rust
+/// #![feature(phantom_variance_markers)]
+///
+/// use core::marker::{PhantomCovariant, variance};
+///
+/// struct BoundFn<F, P, R>
+/// where
+///     F: Fn(P) -> R,
+/// {
+///     function: F,
+///     parameter: P,
+///     return_value: PhantomCovariant<R>,
+/// }
+///
+/// let bound_fn = BoundFn {
+///     function: core::convert::identity,
+///     parameter: 5u8,
+///     return_value: variance(),
+/// };
+/// ```
+pub const fn variance<T>() -> T
+where
+    T: Variance,
+{
+    T::VALUE
+}