Remove tags
diff --git a/src/header.rs b/src/header.rs
index a559e48..82fcf7c 100644
--- a/src/header.rs
+++ b/src/header.rs
@@ -1,4 +1,3 @@
-use core::alloc::Layout;
 use core::cell::UnsafeCell;
 use core::fmt;
 use core::sync::atomic::{AtomicUsize, Ordering};
@@ -6,7 +5,7 @@
 
 use crate::raw::TaskVTable;
 use crate::state::*;
-use crate::utils::{abort_on_panic, extend};
+use crate::utils::abort_on_panic;
 
 /// The header of a task.
 ///
@@ -158,15 +157,6 @@
             abort_on_panic(|| w.wake());
         }
     }
-
-    /// Returns the offset at which the tag of type `T` is stored.
-    #[inline]
-    pub(crate) fn offset_tag<T>() -> usize {
-        let layout_header = Layout::new::<Header>();
-        let layout_t = Layout::new::<T>();
-        let (_, offset_t) = extend(layout_header, layout_t);
-        offset_t
-    }
 }
 
 impl fmt::Debug for Header {
diff --git a/src/join_handle.rs b/src/join_handle.rs
index edf9fcd..e6dbdb8 100644
--- a/src/join_handle.rs
+++ b/src/join_handle.rs
@@ -15,20 +15,20 @@
 ///
 /// * `None` indicates the task has panicked or was canceled.
 /// * `Some(result)` indicates the task has completed with `result` of type `R`.
-pub struct JoinHandle<R, T> {
+pub struct JoinHandle<R> {
     /// A raw task pointer.
     pub(crate) raw_task: NonNull<()>,
 
-    /// A marker capturing generic types `R` and `T`.
-    pub(crate) _marker: PhantomData<(R, T)>,
+    /// A marker capturing generic type `R`.
+    pub(crate) _marker: PhantomData<R>,
 }
 
-unsafe impl<R: Send, T> Send for JoinHandle<R, T> {}
-unsafe impl<R, T> Sync for JoinHandle<R, T> {}
+unsafe impl<R: Send> Send for JoinHandle<R> {}
+unsafe impl<R> Sync for JoinHandle<R> {}
 
-impl<R, T> Unpin for JoinHandle<R, T> {}
+impl<R> Unpin for JoinHandle<R> {}
 
-impl<R, T> JoinHandle<R, T> {
+impl<R> JoinHandle<R> {
     /// Cancels the task.
     ///
     /// If the task has already completed, calling this method will have no effect.
@@ -81,17 +81,6 @@
         }
     }
 
-    /// Returns a reference to the tag stored inside the task.
-    pub fn tag(&self) -> &T {
-        let offset = Header::offset_tag::<T>();
-        let ptr = self.raw_task.as_ptr();
-
-        unsafe {
-            let raw = (ptr as *mut u8).add(offset) as *const T;
-            &*raw
-        }
-    }
-
     /// Returns a waker associated with the task.
     pub fn waker(&self) -> Waker {
         let ptr = self.raw_task.as_ptr();
@@ -104,7 +93,7 @@
     }
 }
 
-impl<R, T> Drop for JoinHandle<R, T> {
+impl<R> Drop for JoinHandle<R> {
     fn drop(&mut self) {
         let ptr = self.raw_task.as_ptr();
         let header = ptr as *const Header;
@@ -185,7 +174,7 @@
     }
 }
 
-impl<R, T> Future for JoinHandle<R, T> {
+impl<R> Future for JoinHandle<R> {
     type Output = Option<R>;
 
     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
@@ -266,7 +255,7 @@
     }
 }
 
-impl<R, T> fmt::Debug for JoinHandle<R, T> {
+impl<R> fmt::Debug for JoinHandle<R> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let ptr = self.raw_task.as_ptr();
         let header = ptr as *const Header;
diff --git a/src/lib.rs b/src/lib.rs
index 3e3cbf6..94afa65 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -39,9 +39,6 @@
 //! task.schedule();
 //! ```
 //!
-//! The last argument to the [`spawn`] function is a *tag*, an arbitrary piece of data associated
-//! with the task. In most executors, this is typically a task identifier or task-local storage.
-//!
 //! The function returns a runnable [`Task`] and a [`JoinHandle`] that can await the result.
 //!
 //! # Execution
diff --git a/src/raw.rs b/src/raw.rs
index 05891d7..0ac0631 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -1,7 +1,6 @@
 use alloc::alloc::Layout;
 use core::cell::UnsafeCell;
 use core::future::Future;
-use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop};
 use core::pin::Pin;
 use core::ptr::NonNull;
@@ -48,9 +47,6 @@
     /// Memory layout of the whole task.
     pub(crate) layout: Layout,
 
-    /// Offset into the task at which the tag is stored.
-    pub(crate) offset_t: usize,
-
     /// Offset into the task at which the schedule function is stored.
     pub(crate) offset_s: usize,
 
@@ -62,16 +58,13 @@
 }
 
 /// Raw pointers to the fields inside a task.
-pub(crate) struct RawTask<F, R, S, T> {
+pub(crate) struct RawTask<F, R, S> {
     /// The task header.
     pub(crate) header: *const Header,
 
     /// The schedule function.
     pub(crate) schedule: *const S,
 
-    /// The tag inside the task.
-    pub(crate) tag: *mut T,
-
     /// The future.
     pub(crate) future: *mut F,
 
@@ -79,18 +72,18 @@
     pub(crate) output: *mut R,
 }
 
-impl<F, R, S, T> Copy for RawTask<F, R, S, T> {}
+impl<F, R, S> Copy for RawTask<F, R, S> {}
 
-impl<F, R, S, T> Clone for RawTask<F, R, S, T> {
+impl<F, R, S> Clone for RawTask<F, R, S> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-impl<F, R, S, T> RawTask<F, R, S, T>
+impl<F, R, S> RawTask<F, R, S>
 where
     F: Future<Output = R> + 'static,
-    S: Fn(Task<T>) + Send + Sync + 'static,
+    S: Fn(Task) + Send + Sync + 'static,
 {
     const RAW_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
         Self::clone_waker,
@@ -102,7 +95,7 @@
     /// Allocates a task with the given `future` and `schedule` function.
     ///
     /// It is assumed that initially only the `Task` reference and the `JoinHandle` exist.
-    pub(crate) fn allocate(future: F, schedule: S, tag: T) -> NonNull<()> {
+    pub(crate) fn allocate(future: F, schedule: S) -> NonNull<()> {
         // Compute the layout of the task for allocation. Abort if the computation fails.
         let task_layout = abort_on_panic(|| Self::task_layout());
 
@@ -130,9 +123,6 @@
                 },
             });
 
-            // Write the tag as the second field of the task.
-            (raw.tag as *mut T).write(tag);
-
             // Write the schedule function as the third field of the task.
             (raw.schedule as *mut S).write(schedule);
 
@@ -152,7 +142,6 @@
         unsafe {
             Self {
                 header: p as *const Header,
-                tag: p.add(task_layout.offset_t) as *mut T,
                 schedule: p.add(task_layout.offset_s) as *const S,
                 future: p.add(task_layout.offset_f) as *mut F,
                 output: p.add(task_layout.offset_r) as *mut R,
@@ -163,9 +152,8 @@
     /// Returns the memory layout for a task.
     #[inline]
     fn task_layout() -> TaskLayout {
-        // Compute the layouts for `Header`, `T`, `S`, `F`, and `R`.
+        // Compute the layouts for `Header`, `S`, `F`, and `R`.
         let layout_header = Layout::new::<Header>();
-        let layout_t = Layout::new::<T>();
         let layout_s = Layout::new::<S>();
         let layout_f = Layout::new::<F>();
         let layout_r = Layout::new::<R>();
@@ -175,9 +163,8 @@
         let align_union = layout_f.align().max(layout_r.align());
         let layout_union = unsafe { Layout::from_size_align_unchecked(size_union, align_union) };
 
-        // Compute the layout for `Header` followed by `T`, then `S`, and finally `union { F, R }`.
+        // Compute the layout for `Header` followed `S` and `union { F, R }`.
         let layout = layout_header;
-        let (layout, offset_t) = extend(layout, layout_t);
         let (layout, offset_s) = extend(layout, layout_s);
         let (layout, offset_union) = extend(layout, layout_union);
         let offset_f = offset_union;
@@ -185,7 +172,6 @@
 
         TaskLayout {
             layout,
-            offset_t,
             offset_s,
             offset_f,
             offset_r,
@@ -311,7 +297,6 @@
                             // still alive.
                             let task = Task {
                                 raw_task: NonNull::new_unchecked(ptr as *mut ()),
-                                _marker: PhantomData,
                             };
                             (*raw.schedule)(task);
                         }
@@ -403,7 +388,6 @@
 
         let task = Task {
             raw_task: NonNull::new_unchecked(ptr as *mut ()),
-            _marker: PhantomData,
         };
         (*raw.schedule)(task);
     }
@@ -427,7 +411,7 @@
 
     /// Cleans up task's resources and deallocates it.
     ///
-    /// The schedule function and the tag will be dropped, and the task will then get deallocated.
+    /// The schedule function will be dropped, and the task will then get deallocated.
     /// The task must be closed before this function is called.
     #[inline]
     unsafe fn destroy(ptr: *const ()) {
@@ -438,9 +422,6 @@
         abort_on_panic(|| {
             // Drop the schedule function.
             (raw.schedule as *mut S).drop_in_place();
-
-            // Drop the tag.
-            (raw.tag as *mut T).drop_in_place();
         });
 
         // Finally, deallocate the memory reserved by the task.
@@ -609,15 +590,15 @@
         return false;
 
         /// A guard that closes the task if polling its future panics.
-        struct Guard<F, R, S, T>(RawTask<F, R, S, T>)
+        struct Guard<F, R, S>(RawTask<F, R, S>)
         where
             F: Future<Output = R> + 'static,
-            S: Fn(Task<T>) + Send + Sync + 'static;
+            S: Fn(Task) + Send + Sync + 'static;
 
-        impl<F, R, S, T> Drop for Guard<F, R, S, T>
+        impl<F, R, S> Drop for Guard<F, R, S>
         where
             F: Future<Output = R> + 'static,
-            S: Fn(Task<T>) + Send + Sync + 'static,
+            S: Fn(Task) + Send + Sync + 'static,
         {
             fn drop(&mut self) {
                 let raw = self.0;
@@ -632,7 +613,7 @@
                         if state & CLOSED != 0 {
                             // The thread that closed the task didn't drop the future because it
                             // was running so now it's our responsibility to do so.
-                            RawTask::<F, R, S, T>::drop_future(ptr);
+                            RawTask::<F, R, S>::drop_future(ptr);
 
                             // Mark the task as not running and not scheduled.
                             (*raw.header)
@@ -645,7 +626,7 @@
                             }
 
                             // Drop the task reference.
-                            RawTask::<F, R, S, T>::drop_task(ptr);
+                            RawTask::<F, R, S>::drop_task(ptr);
                             break;
                         }
 
@@ -658,7 +639,7 @@
                         ) {
                             Ok(state) => {
                                 // Drop the future because the task is now closed.
-                                RawTask::<F, R, S, T>::drop_future(ptr);
+                                RawTask::<F, R, S>::drop_future(ptr);
 
                                 // Notify the awaiter that the future has been dropped.
                                 if state & AWAITER != 0 {
@@ -666,7 +647,7 @@
                                 }
 
                                 // Drop the task reference.
-                                RawTask::<F, R, S, T>::drop_task(ptr);
+                                RawTask::<F, R, S>::drop_task(ptr);
                                 break;
                             }
                             Err(s) => state = s,
diff --git a/src/task.rs b/src/task.rs
index 4d60f07..6fb4cad 100644
--- a/src/task.rs
+++ b/src/task.rs
@@ -17,7 +17,7 @@
 /// awaits its result.
 ///
 /// When run, the task polls `future`. When woken up, it gets scheduled for running by the
-/// `schedule` function. Argument `tag` is an arbitrary piece of data stored inside the task.
+/// `schedule` function.
 ///
 /// The schedule function should not attempt to run the task nor to drop it. Instead, it should
 /// push the task into some kind of queue so that it can be processed later.
@@ -47,24 +47,22 @@
 /// // Create a task with the future and the schedule function.
 /// let (task, handle) = async_task::spawn(future, schedule, ());
 /// ```
-pub fn spawn<F, R, S, T>(future: F, schedule: S, tag: T) -> (Task<T>, JoinHandle<R, T>)
+pub fn spawn<F, R, S>(future: F, schedule: S) -> (Task, JoinHandle<R>)
 where
     F: Future<Output = R> + Send + 'static,
     R: Send + 'static,
-    S: Fn(Task<T>) + Send + Sync + 'static,
-    T: Send + Sync + 'static,
+    S: Fn(Task) + Send + Sync + 'static,
 {
     // Allocate large futures on the heap.
     let raw_task = if mem::size_of::<F>() >= 2048 {
         let future = alloc::boxed::Box::pin(future);
-        RawTask::<_, R, S, T>::allocate(future, schedule, tag)
+        RawTask::<_, R, S>::allocate(future, schedule)
     } else {
-        RawTask::<F, R, S, T>::allocate(future, schedule, tag)
+        RawTask::<F, R, S>::allocate(future, schedule)
     };
 
     let task = Task {
         raw_task,
-        _marker: PhantomData,
     };
     let handle = JoinHandle {
         raw_task,
@@ -79,7 +77,7 @@
 /// awaits its result.
 ///
 /// When run, the task polls `future`. When woken up, it gets scheduled for running by the
-/// `schedule` function. Argument `tag` is an arbitrary piece of data stored inside the task.
+/// `schedule` function.
 ///
 /// The schedule function should not attempt to run the task nor to drop it. Instead, it should
 /// push the task into some kind of queue so that it can be processed later.
@@ -113,12 +111,11 @@
 /// let (task, handle) = async_task::spawn_local(future, schedule, ());
 /// ```
 #[cfg(feature = "std")]
-pub fn spawn_local<F, R, S, T>(future: F, schedule: S, tag: T) -> (Task<T>, JoinHandle<R, T>)
+pub fn spawn_local<F, R, S>(future: F, schedule: S) -> (Task, JoinHandle<R>)
 where
     F: Future<Output = R> + 'static,
     R: 'static,
-    S: Fn(Task<T>) + Send + Sync + 'static,
-    T: Send + Sync + 'static,
+    S: Fn(Task) + Send + Sync + 'static,
 {
     extern crate std;
 
@@ -175,14 +172,13 @@
     // Allocate large futures on the heap.
     let raw_task = if mem::size_of::<F>() >= 2048 {
         let future = alloc::boxed::Box::pin(future);
-        RawTask::<_, R, S, T>::allocate(future, schedule, tag)
+        RawTask::<_, R, S>::allocate(future, schedule)
     } else {
-        RawTask::<_, R, S, T>::allocate(future, schedule, tag)
+        RawTask::<_, R, S>::allocate(future, schedule)
     };
 
     let task = Task {
         raw_task,
-        _marker: PhantomData,
     };
     let handle = JoinHandle {
         raw_task,
@@ -211,18 +207,15 @@
 /// [`JoinHandle`]: struct.JoinHandle.html
 /// [`Task`]: struct.Task.html
 /// [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html
-pub struct Task<T> {
+pub struct Task {
     /// A pointer to the heap-allocated task.
     pub(crate) raw_task: NonNull<()>,
-
-    /// A marker capturing the generic type `T`.
-    pub(crate) _marker: PhantomData<T>,
 }
 
-unsafe impl<T> Send for Task<T> {}
-unsafe impl<T> Sync for Task<T> {}
+unsafe impl Send for Task {}
+unsafe impl Sync for Task {}
 
-impl<T> Task<T> {
+impl Task {
     /// Schedules the task.
     ///
     /// This is a convenience method that simply reschedules the task by passing it to its schedule
@@ -280,38 +273,21 @@
         }
     }
 
-    /// Returns a reference to the tag stored inside the task.
-    pub fn tag(&self) -> &T {
-        let offset = Header::offset_tag::<T>();
-        let ptr = self.raw_task.as_ptr();
-
-        unsafe {
-            let raw = (ptr as *mut u8).add(offset) as *const T;
-            &*raw
-        }
-    }
-
-    /// Converts this task into a raw pointer to the tag.
-    pub fn into_raw(self) -> *const T {
-        let offset = Header::offset_tag::<T>();
+    /// Converts this task into a raw pointer.
+    pub fn into_raw(self) -> *mut () {
         let ptr = self.raw_task.as_ptr();
         mem::forget(self);
-
-        unsafe { (ptr as *mut u8).add(offset) as *const T }
+        ptr
     }
 
-    /// Converts a raw pointer to the tag into a task.
+    /// Converts a raw pointer into a task.
     ///
     /// This method should only be used with raw pointers returned from [`into_raw`].
     ///
     /// [`into_raw`]: #method.into_raw
-    pub unsafe fn from_raw(raw: *const T) -> Task<T> {
-        let offset = Header::offset_tag::<T>();
-        let ptr = (raw as *mut u8).sub(offset) as *mut ();
-
+    pub unsafe fn from_raw(raw: *mut ()) -> Task {
         Task {
-            raw_task: NonNull::new_unchecked(ptr),
-            _marker: PhantomData,
+            raw_task: NonNull::new_unchecked(raw as *mut ()),
         }
     }
 
@@ -327,7 +303,7 @@
     }
 }
 
-impl<T> Drop for Task<T> {
+impl Drop for Task {
     fn drop(&mut self) {
         let ptr = self.raw_task.as_ptr();
         let header = ptr as *const Header;
@@ -353,14 +329,13 @@
     }
 }
 
-impl<T: fmt::Debug> fmt::Debug for Task<T> {
+impl fmt::Debug for Task {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let ptr = self.raw_task.as_ptr();
         let header = ptr as *const Header;
 
         f.debug_struct("Task")
             .field("header", unsafe { &(*header) })
-            .field("tag", self.tag())
             .finish()
     }
 }