Skip to content

Commit 60a65cd

Browse files
committed
Feature-gate #[derive_*] even when produced by macro expansion.
1 parent b0d3170 commit 60a65cd

File tree

4 files changed

+82
-11
lines changed

4 files changed

+82
-11
lines changed

src/libsyntax/feature_gate.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -724,9 +724,7 @@ impl<'a> Context<'a> {
724724
with the prefix `rustc_` \
725725
are reserved for internal compiler diagnostics");
726726
} else if name.starts_with("derive_") {
727-
self.gate_feature("custom_derive", attr.span,
728-
"attributes of the form `#[derive_*]` are reserved \
729-
for the compiler");
727+
self.gate_feature("custom_derive", attr.span, EXPLAIN_DERIVE_UNDERSCORE);
730728
} else {
731729
// Only run the custom attribute lint during regular
732730
// feature gate checking. Macro gating runs
@@ -801,6 +799,8 @@ pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
801799

802800
pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
803801
"`#[derive]` for custom traits is not stable enough for use and is subject to change";
802+
pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
803+
"attributes of the form `#[derive_*]` are reserved for the compiler";
804804

805805
struct MacroVisitor<'a> {
806806
context: &'a Context<'a>

src/libsyntax_ext/deriving/mod.rs

+28-8
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ fn expand_derive(cx: &mut ExtCtxt,
9696
let mut found_partial_eq = false;
9797
let mut found_eq = false;
9898

99+
// See below for how this is used with #[structural_match].
100+
let unstable_span = Span { expn_id: cx.backtrace(), .. span };
101+
assert!(cx.parse_sess.codemap().span_allows_unstable(unstable_span));
102+
99103
for titem in traits.iter().rev() {
100104
let tname = match titem.node {
101105
MetaItemKind::Word(ref tname) => tname,
@@ -120,8 +124,18 @@ fn expand_derive(cx: &mut ExtCtxt,
120124
found_partial_eq = true;
121125
}
122126

127+
// Mark the attributes we generate as allowing unstable code,
128+
// to bypass the feature-gating of #[derive_*] attributes.
129+
let mut tspan = titem.span;
130+
tspan.expn_id = unstable_span.expn_id;
131+
if !cx.parse_sess.codemap().span_allows_unstable(tspan) {
132+
// If we can't use the trait span, use the full #[...] span.
133+
// See below for how this works with #[structural_match].
134+
tspan = unstable_span;
135+
}
136+
123137
// #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
124-
item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
138+
item.attrs.push(cx.attribute(tspan, cx.meta_word(tspan,
125139
intern_and_get_ident(&format!("derive_{}", tname)))));
126140
}
127141

@@ -155,12 +169,10 @@ fn expand_derive(cx: &mut ExtCtxt,
155169
//
156170
// See tests src/run-pass/rfc1445 for
157171
// examples. --nmatsakis
158-
let span = Span { expn_id: cx.backtrace(), .. span };
159-
assert!(cx.parse_sess.codemap().span_allows_unstable(span));
160-
debug!("inserting structural_match with span {:?}", span);
172+
debug!("inserting structural_match with span {:?}", unstable_span);
161173
let structural_match = intern_and_get_ident("structural_match");
162-
item.attrs.push(cx.attribute(span,
163-
cx.meta_word(span,
174+
item.attrs.push(cx.attribute(unstable_span,
175+
cx.meta_word(unstable_span,
164176
structural_match)));
165177
}
166178

@@ -188,7 +200,7 @@ macro_rules! derive_traits {
188200
mitem: &MetaItem,
189201
annotatable: &Annotatable,
190202
push: &mut FnMut(Annotatable)) {
191-
warn_if_deprecated(ecx, sp, $name);
203+
check_builtin_derive(ecx, sp, $name);
192204
$func(ecx, sp, mitem, annotatable, push);
193205
}
194206
}
@@ -238,7 +250,15 @@ derive_traits! {
238250
}
239251

240252
#[inline] // because `name` is a compile-time constant
241-
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
253+
fn check_builtin_derive(ecx: &mut ExtCtxt, sp: Span, name: &str) {
254+
let allows_unstable = ecx.parse_sess.codemap().span_allows_unstable(sp);
255+
if !(allows_unstable || ecx.ecfg.enable_custom_derive()) {
256+
feature_gate::emit_feature_err(&ecx.parse_sess.span_diagnostic,
257+
"custom_derive",
258+
sp,
259+
feature_gate::GateIssue::Language,
260+
feature_gate::EXPLAIN_DERIVE_UNDERSCORE);
261+
}
242262
if let Some(replacement) = match name {
243263
"Encodable" => Some("RustcEncodable"),
244264
"Decodable" => Some("RustcDecodable"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
macro_rules! expand_to_unstable {
12+
() => {
13+
#[derive_Clone]
14+
//~^ ERROR attributes of the form `#[derive_*]` are reserved
15+
struct Test;
16+
}
17+
}
18+
19+
expand_to_unstable!();
20+
21+
pub fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-pretty : (#23623) problems when ending with // comments
12+
13+
#![feature(allow_internal_unstable)]
14+
15+
#[allow_internal_unstable]
16+
macro_rules! expand_to_unstable {
17+
() => {
18+
// FIXME(eddyb) #[allow_internal_unstable]
19+
// doesn't actually work for some reason.
20+
21+
#[derive(Clone)] //#[derive_Clone]
22+
struct Test;
23+
}
24+
}
25+
26+
expand_to_unstable!();
27+
28+
pub fn main() {
29+
Test.clone();
30+
}

0 commit comments

Comments
 (0)