diff --git a/src/doc/reference.md b/src/doc/reference.md
index 94c76aaa6951..b6684c560c85 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -2436,8 +2436,12 @@ impl<T: PartialEq> PartialEq for Foo<T> {
 Supported traits for `deriving` are:
 
 * Comparison traits: `PartialEq`, `Eq`, `PartialOrd`, `Ord`.
-* Serialization: `Encodable`, `Decodable`. These require `serialize`.
-* `Clone`, to create `T` from `&T` via a copy.
+* Serialization: `RustcEncodable`, `RustcDecodable`. These require `serialize`.
+* `Clone`, to create `T` from `&T` via cloning its contents.
+* `Copy`, to indicate that this type is allowed to be copied bitwise (if
+  safe).
+* `Sync`, to indicate that this type is safe to use concurrently.
+* `Send`, to indicate that this type
 * `Default`, to create an empty instance of a data type.
 * `FromPrimitive`, to create an instance from a numeric primitive.
 * `Hash`, to iterate over the bytes in a data type.
@@ -2445,6 +2449,14 @@ Supported traits for `deriving` are:
 * `Show`, to format a value using the `{}` formatter.
 * `Zero`, to create a zero instance of a numeric data type.
 
+Each derived trait can have attributes applied to the generated `impl`, such
+as:
+
+```
+#[deriving(Clone(attributes(cfg(not(windows)), unstable)))]
+struct X
+```
+
 ### Stability
 
 One can indicate the stability of an API using the following attributes:
@@ -4149,11 +4161,11 @@ Unwinding the stack of a thread is done by the thread itself, on its own control
 stack. If a value with a destructor is freed during unwinding, the code for the
 destructor is run, also on the thread's control stack. Running the destructor
 code causes a temporary transition to a *running* state, and allows the
-destructor code to cause any subsequent state transitions. The original thread 
+destructor code to cause any subsequent state transitions. The original thread
 of unwinding and panicking thereby may suspend temporarily, and may involve
 (recursive) unwinding of the stack of a failed destructor. Nonetheless, the
 outermost unwinding activity will continue until the stack is unwound and the
-thread transitions to the *dead* state. There is no way to "recover" from thread 
+thread transitions to the *dead* state. There is no way to "recover" from thread
 panics. Once a thread has temporarily suspended its unwinding in the *panicking*
 state, a panic occurring from within this destructor results in *hard* panic.
 A hard panic currently results in the process aborting.
diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs
index cf29bb048d64..eb832b0967d0 100644
--- a/src/libsyntax/ext/deriving/bounds.rs
+++ b/src/libsyntax/ext/deriving/bounds.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{MetaItem, MetaWord, Item};
+use ast::{MetaItem, MetaWord, MetaList, Item};
 use codemap::Span;
 use ext::base::ExtCtxt;
 use ext::deriving::generic::*;
@@ -23,7 +23,8 @@ pub fn expand_deriving_bound<F>(cx: &mut ExtCtxt,
     F: FnOnce(P<Item>),
 {
     let name = match mitem.node {
-        MetaWord(ref tname) => {
+        MetaWord(ref tname) |
+        MetaList(ref tname, _) => {
             match tname.get() {
                 "Copy" => "Copy",
                 "Send" | "Sync" => {
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index 75f763b5c38e..8fb73f3eedba 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -13,9 +13,10 @@
 //! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
 //! the standard library, and "std" is the core library.
 
-use ast::{Item, MetaItem, MetaList, MetaNameValue, MetaWord};
+use attr::{mk_attr_id, AttrMetaMethods};
+use ast::{AttrStyle, Attribute_, Item, MetaItem, MetaList, MetaNameValue, MetaWord};
 use ext::base::ExtCtxt;
-use codemap::Span;
+use codemap::{Span, Spanned};
 use ptr::P;
 
 pub mod bounds;
@@ -58,14 +59,59 @@ pub fn expand_meta_deriving(cx: &mut ExtCtxt,
         }
         MetaList(_, ref titems) => {
             for titem in titems.iter().rev() {
+                let mut attrs = Vec::new();
+                match titem.node {
+                    MetaNameValue(_, _) |
+                    MetaWord(_) => { }
+                    MetaList(_, ref alist) => {
+                        if alist.len() != 1 {
+                            cx.span_err(titem.span, "unexpected syntax in `deriving`")
+                        } else {
+                            let alist = &alist[0];
+                            if alist.name().get() == "attributes" {
+                                match alist.meta_item_list() {
+                                    None => cx.span_err(alist.span,
+                                                        "unexpected syntax in `deriving`"),
+                                    Some(metas) => {
+                                        for meta in metas.iter() {
+                                            attrs.push(Spanned {
+                                                span: meta.span,
+                                                node: Attribute_ {
+                                                    id: mk_attr_id(),
+                                                    style: AttrStyle::AttrOuter,
+                                                    value: meta.clone() /* bad clone */,
+                                                    is_sugared_doc: false
+                                                }
+                                            });
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // so we don't need to clone in the closure below. we also can't move,
+                // unfortunately, since it would capture the outer `push` as well.
+                let mut attrs = Some(attrs);
+
                 match titem.node {
                     MetaNameValue(ref tname, _) |
                     MetaList(ref tname, _) |
                     MetaWord(ref tname) => {
-                        macro_rules! expand(($func:path) => ($func(cx, titem.span,
-                                                                   &**titem, item,
-                                                                   |i| push.call_mut((i,)))));
+                        // note: for the unwrap to succeed, this macro can't be evaluated more than
+                        // once in any control flow branch. don't use it twice in a match arm
+                        // below!
+                        macro_rules! expand(
+                            ($func:path) =>
+                            ($func(cx, titem.span, &**titem, item,
+                                   |i| push.call_mut((i.map(|mut i| {
+                                       i.attrs.extend(attrs.take().unwrap().into_iter());
+                                       i
+                                   }),)))));
                         match tname.get() {
+                            // if you change this list without updating reference.md, cmr will be
+                            // sad
                             "Clone" => expand!(clone::expand_deriving_clone),
 
                             "Hash" => expand!(hash::expand_deriving_hash),
diff --git a/src/test/run-pass/deriving-add-attributes.rs b/src/test/run-pass/deriving-add-attributes.rs
new file mode 100644
index 000000000000..fec9aa0c7424
--- /dev/null
+++ b/src/test/run-pass/deriving-add-attributes.rs
@@ -0,0 +1,14 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[deriving(Copy(attributes(stable)), Clone(attributes(unstable)))]
+struct X;
+
+fn main() {}