Skip to content

Commit 99c2a6b

Browse files
committed
modify #[deriving(Eq)] to emit #[structural_match]
to careful use of the span from deriving, we can permit it in stable code if it derives from deriving (not-even-a-pun intended)
1 parent 5bc2868 commit 99c2a6b

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

src/libsyntax/feature_gate.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
109109
// to bootstrap fix for #5723.
110110
("issue_5723_bootstrap", "1.0.0", None, Accepted),
111111

112+
("structural_match", "1.8.0", Some(31434), Active),
113+
112114
// A way to temporarily opt out of opt in copy. This will *never* be accepted.
113115
("opt_out_copy", "1.0.0", None, Removed),
114116

@@ -304,6 +306,11 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
304306
("link_args", Normal, Ungated),
305307
("macro_escape", Normal, Ungated),
306308

309+
// RFC #1445.
310+
("structural_match", Whitelisted, Gated("structural_match",
311+
"the semantics of constant patterns is \
312+
not yet settled")),
313+
307314
// Not used any more, but we can't feature gate it
308315
("no_stack_check", Normal, Ungated),
309316

@@ -676,7 +683,7 @@ impl<'a> Context<'a> {
676683
fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
677684
let has_feature = self.has_feature(feature);
678685
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
679-
if !has_feature {
686+
if !has_feature && !self.cm.span_allows_unstable(span) {
680687
emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
681688
}
682689
}

src/libsyntax_ext/deriving/mod.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ fn expand_derive(cx: &mut ExtCtxt,
7878
mitem: &MetaItem,
7979
annotatable: Annotatable)
8080
-> Annotatable {
81-
annotatable.map_item_or(|item| {
81+
debug!("expand_derive: span = {:?}", span);
82+
debug!("expand_derive: mitem = {:?}", mitem);
83+
debug!("expand_derive: annotatable input = {:?}", annotatable);
84+
let annot = annotatable.map_item_or(|item| {
8285
item.map(|mut item| {
8386
if mitem.value_str().is_some() {
8487
cx.span_err(mitem.span, "unexpected value in `derive`");
@@ -107,6 +110,45 @@ fn expand_derive(cx: &mut ExtCtxt,
107110
continue;
108111
}
109112

113+
// RFC #1445. `#[derive(Eq)]` adds a (trusted)
114+
// `#[structural_match]` attribute.
115+
if &tname[..] == "Eq" {
116+
// This span is **very** sensitive and crucial to
117+
// getting the stability behavior we want. What we
118+
// are doing is marking `#[structural_match]` with
119+
// the span of the `#[deriving(Eq)]` attribute
120+
// (the entire attribute, not just the `Eq` part),
121+
// but with the current backtrace. The current
122+
// backtrace will contain a topmost entry that IS
123+
// this `#[deriving(Eq)]` attribute and with the
124+
// "allow-unstable" flag set to true.
125+
//
126+
// Note that we do NOT use the span of the `Eq`
127+
// text itself. You might think this is
128+
// equivalent, because the `Eq` appears within the
129+
// `#[deriving(Eq)]` attribute, and hence we would
130+
// inherit the "allows unstable" from the
131+
// backtrace. But in fact this is not always the
132+
// case. The actual source text that led to
133+
// deriving can be `#[$attr]`, for example, where
134+
// `$attr == deriving(Eq)`. In that case, the
135+
// "#[structural_match]" would be considered to
136+
// originate not from the deriving call but from
137+
// text outside the deriving call, and hence would
138+
// be forbidden from using unstable
139+
// content.
140+
//
141+
// See tests src/run-pass/rfc1445 for
142+
// examples. --nmatsakis
143+
let span = Span { expn_id: cx.backtrace(), .. span };
144+
assert!(cx.parse_sess.codemap().span_allows_unstable(span));
145+
debug!("inserting structural_match with span {:?}", span);
146+
let structural_match = intern_and_get_ident("structural_match");
147+
item.attrs.push(cx.attribute(span,
148+
cx.meta_word(span,
149+
structural_match)));
150+
}
151+
110152
// #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
111153
item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
112154
intern_and_get_ident(&format!("derive_{}", tname)))));
@@ -117,7 +159,9 @@ fn expand_derive(cx: &mut ExtCtxt,
117159
}, |a| {
118160
cx.span_err(span, "`derive` can only be applied to items");
119161
a
120-
})
162+
});
163+
debug!("expand_derive: annotatable output = {:?}", annot);
164+
annot
121165
}
122166

123167
macro_rules! derive_traits {

src/libsyntax_ext/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#![feature(str_char)]
2525

2626
extern crate fmt_macros;
27+
#[macro_use] extern crate log;
2728
#[macro_use]
2829
extern crate syntax;
2930

0 commit comments

Comments
 (0)