Skip to content

Feature-gate #[derive_*] even when produced by macro expansion. #32671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,9 +724,7 @@ impl<'a> Context<'a> {
with the prefix `rustc_` \
are reserved for internal compiler diagnostics");
} else if name.starts_with("derive_") {
self.gate_feature("custom_derive", attr.span,
"attributes of the form `#[derive_*]` are reserved \
for the compiler");
self.gate_feature("custom_derive", attr.span, EXPLAIN_DERIVE_UNDERSCORE);
} else {
// Only run the custom attribute lint during regular
// feature gate checking. Macro gating runs
Expand Down Expand Up @@ -801,6 +799,8 @@ pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =

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

struct MacroVisitor<'a> {
context: &'a Context<'a>
Expand Down
36 changes: 28 additions & 8 deletions src/libsyntax_ext/deriving/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ fn expand_derive(cx: &mut ExtCtxt,
let mut found_partial_eq = false;
let mut found_eq = false;

// See below for how this is used with #[structural_match].
let unstable_span = Span { expn_id: cx.backtrace(), .. span };
assert!(cx.parse_sess.codemap().span_allows_unstable(unstable_span));

for titem in traits.iter().rev() {
let tname = match titem.node {
MetaItemKind::Word(ref tname) => tname,
Expand All @@ -120,8 +124,18 @@ fn expand_derive(cx: &mut ExtCtxt,
found_partial_eq = true;
}

// Mark the attributes we generate as allowing unstable code,
// to bypass the feature-gating of #[derive_*] attributes.
let mut tspan = titem.span;
tspan.expn_id = unstable_span.expn_id;
if !cx.parse_sess.codemap().span_allows_unstable(tspan) {
// If we can't use the trait span, use the full #[...] span.
// See below for how this works with #[structural_match].
tspan = unstable_span;
}

// #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
item.attrs.push(cx.attribute(tspan, cx.meta_word(tspan,
intern_and_get_ident(&format!("derive_{}", tname)))));
}

Expand Down Expand Up @@ -155,12 +169,10 @@ fn expand_derive(cx: &mut ExtCtxt,
//
// See tests src/run-pass/rfc1445 for
// examples. --nmatsakis
let span = Span { expn_id: cx.backtrace(), .. span };
assert!(cx.parse_sess.codemap().span_allows_unstable(span));
debug!("inserting structural_match with span {:?}", span);
debug!("inserting structural_match with span {:?}", unstable_span);
let structural_match = intern_and_get_ident("structural_match");
item.attrs.push(cx.attribute(span,
cx.meta_word(span,
item.attrs.push(cx.attribute(unstable_span,
cx.meta_word(unstable_span,
structural_match)));
}

Expand Down Expand Up @@ -188,7 +200,7 @@ macro_rules! derive_traits {
mitem: &MetaItem,
annotatable: &Annotatable,
push: &mut FnMut(Annotatable)) {
warn_if_deprecated(ecx, sp, $name);
check_builtin_derive(ecx, sp, $name);
$func(ecx, sp, mitem, annotatable, push);
}
}
Expand Down Expand Up @@ -238,7 +250,15 @@ derive_traits! {
}

#[inline] // because `name` is a compile-time constant
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
fn check_builtin_derive(ecx: &mut ExtCtxt, sp: Span, name: &str) {
let allows_unstable = ecx.parse_sess.codemap().span_allows_unstable(sp);
if !(allows_unstable || ecx.ecfg.enable_custom_derive()) {
feature_gate::emit_feature_err(&ecx.parse_sess.span_diagnostic,
"custom_derive",
sp,
feature_gate::GateIssue::Language,
feature_gate::EXPLAIN_DERIVE_UNDERSCORE);
}
if let Some(replacement) = match name {
"Encodable" => Some("RustcEncodable"),
"Decodable" => Some("RustcDecodable"),
Expand Down
21 changes: 21 additions & 0 deletions src/test/compile-fail/single-derive-attr-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2015 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.

macro_rules! expand_to_unstable {
() => {
#[derive_Clone]
//~^ ERROR attributes of the form `#[derive_*]` are reserved
struct Test;
}
}

expand_to_unstable!();

pub fn main() {}
30 changes: 30 additions & 0 deletions src/test/run-pass/single-derive-attr-allow-unstable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2016 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.

// ignore-pretty : (#23623) problems when ending with // comments

#![feature(allow_internal_unstable)]

#[allow_internal_unstable]
macro_rules! expand_to_unstable {
() => {
// FIXME(eddyb) #[allow_internal_unstable]
// doesn't actually work for some reason.

#[derive(Clone)] //#[derive_Clone]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't get this to work, seems like the span_allows_unstable check isn't enough.
cc @pnkfelix @nrc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't you need to also turn on the feature gate for #[derive_X] syntax? Is there even such a gate? namely #![feature(custom_derive)]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is, custom_derive, but allow_internal_unstable is supposed to bypass the actual feature gating (i.e. any feature can be used inside an #[allow_internal_unstable] macro).
This works with, e.g. #[thread_local] static FOO: usize = 0;, but not #[derive_Clone].

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, nevermind then, I thought it looked at the actual features enabled in the macro-declaring crate.

struct Test;
}
}

expand_to_unstable!();

pub fn main() {
Test.clone();
}