Skip to content
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

check stability of macro invocations #48524

Merged
merged 1 commit into from
Mar 16, 2018
Merged
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
7 changes: 5 additions & 2 deletions src/librustc_plugin/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,16 @@ impl<'a> Registry<'a> {
expander,
def_info: _,
allow_internal_unstable,
allow_internal_unsafe
allow_internal_unsafe,
unstable_feature
} => {
let nid = ast::CRATE_NODE_ID;
NormalTT {
expander,
def_info: Some((nid, self.krate_span)),
allow_internal_unstable,
allow_internal_unsafe
allow_internal_unsafe,
unstable_feature
}
}
IdentTT(ext, _, allow_internal_unstable) => {
Expand Down Expand Up @@ -149,6 +151,7 @@ impl<'a> Registry<'a> {
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
unstable_feature: None,
});
}

Expand Down
4 changes: 4 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,8 @@ pub enum SyntaxExtension {
/// Whether the contents of the macro can use `unsafe`
/// without triggering the `unsafe_code` lint.
allow_internal_unsafe: bool,
/// The macro's feature name if it is unstable, and the stability feature
unstable_feature: Option<(Symbol, u32)>,
},

/// A function-like syntax extension that has an extra ident before
Expand Down Expand Up @@ -670,6 +672,7 @@ pub struct ExpansionData {
pub depth: usize,
pub module: Rc<ModuleData>,
pub directory_ownership: DirectoryOwnership,
pub crate_span: Option<Span>,
}

/// One of these is made during expansion and incrementally updated as we go;
Expand Down Expand Up @@ -701,6 +704,7 @@ impl<'a> ExtCtxt<'a> {
depth: 0,
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
directory_ownership: DirectoryOwnership::Owned { relative: None },
crate_span: None,
},
expansions: HashMap::new(),
}
Expand Down
56 changes: 40 additions & 16 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use ext::base::*;
use ext::derive::{add_derived_markers, collect_derives};
use ext::hygiene::{Mark, SyntaxContext};
use ext::placeholders::{placeholder, PlaceholderExpander};
use feature_gate::{self, Features, is_builtin_attr};
use feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
use fold;
use fold::*;
use parse::{DirectoryOwnership, PResult};
Expand Down Expand Up @@ -229,6 +229,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
module.directory.pop();
self.cx.root_path = module.directory.clone();
self.cx.current_expansion.module = Rc::new(module);
self.cx.current_expansion.crate_span = Some(krate.span);

let orig_mod_span = krate.module.inner;

Expand Down Expand Up @@ -531,11 +532,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let path = &mac.node.path;

let ident = ident.unwrap_or_else(|| keywords::Invalid.ident());
let validate_and_set_expn_info = |def_site_span,
let validate_and_set_expn_info = |this: &mut Self, // arg instead of capture
def_site_span: Option<Span>,
allow_internal_unstable,
allow_internal_unsafe| {
allow_internal_unsafe,
// can't infer this type
unstable_feature: Option<(Symbol, u32)>| {

// feature-gate the macro invocation
if let Some((feature, issue)) = unstable_feature {
let crate_span = this.cx.current_expansion.crate_span.unwrap();
// don't stability-check macros in the same crate
// (the only time this is null is for syntax extensions registered as macros)
if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span))
&& !span.allows_unstable() && this.cx.ecfg.features.map_or(true, |feats| {
// macro features will count as lib features
!feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature)
}) {
let explain = format!("macro {}! is unstable", path);
emit_feature_err(this.cx.parse_sess, &*feature.as_str(), span,
GateIssue::Library(Some(issue)), &explain);
this.cx.trace_macros_diag();
return Err(kind.dummy(span));
}
}

if ident.name != keywords::Invalid.name() {
return Err(format!("macro {}! expects no ident argument, given '{}'", path, ident));
let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident);
this.cx.span_err(path.span, &msg);
this.cx.trace_macros_diag();
return Err(kind.dummy(span));
}
mark.set_expn_info(ExpnInfo {
call_site: span,
Expand All @@ -551,11 +577,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {

let opt_expanded = match *ext {
DeclMacro(ref expand, def_span) => {
if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s),
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add a test for macros 2.0 (macro m { ... }) as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

Wait, I see, the stability information is not filled for macros 2.0.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It can be if we want it to.

Copy link
Contributor

Choose a reason for hiding this comment

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

We certainly want it, stability of macro items not being checked is a bug in the same way as stability of macro_rules not being checked.

false, false) {
self.cx.span_err(path.span, &msg);
self.cx.trace_macros_diag();
kind.dummy(span)
if let Err(dummy_span) = validate_and_set_expn_info(self, def_span.map(|(_, s)| s),
false, false, None) {
dummy_span
} else {
kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
}
Expand All @@ -565,14 +589,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
ref expander,
def_info,
allow_internal_unstable,
allow_internal_unsafe
allow_internal_unsafe,
unstable_feature,
} => {
if let Err(msg) = validate_and_set_expn_info(def_info.map(|(_, s)| s),
allow_internal_unstable,
allow_internal_unsafe) {
self.cx.span_err(path.span, &msg);
self.cx.trace_macros_diag();
kind.dummy(span)
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
allow_internal_unstable,
allow_internal_unsafe,
unstable_feature) {
dummy_span
} else {
kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
}
Expand Down
13 changes: 12 additions & 1 deletion src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,22 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
if body.legacy {
let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");

let unstable_feature = attr::find_stability(&sess.span_diagnostic,
&def.attrs, def.span).and_then(|stability| {
if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
Some((stability.feature, issue))
} else {
None
}
});

NormalTT {
expander,
def_info: Some((def.id, def.span)),
allow_internal_unstable,
allow_internal_unsafe
allow_internal_unsafe,
unstable_feature
}
} else {
SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)))
Expand Down
2 changes: 2 additions & 0 deletions src/libsyntax_ext/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
unstable_feature: None,
});
)* }
}
Expand Down Expand Up @@ -120,6 +121,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
def_info: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
unstable_feature: None
});

for (name, ext) in user_exts {
Expand Down
16 changes: 16 additions & 0 deletions src/test/compile-fail/auxiliary/unstable-macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 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.

#![feature(staged_api)]
#![stable(feature = "unit_test", since = "0.0.0")]

#[unstable(feature = "unstable_macros", issue = "0")]
#[macro_export]
macro_rules! unstable_macro{ () => () }
22 changes: 22 additions & 0 deletions src/test/compile-fail/macro-stability.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2018 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.

// aux-build:unstable-macros.rs

#![feature(staged_api)]
#[macro_use] extern crate unstable_macros;

#[unstable(feature = "local_unstable", issue = "0")]
macro_rules! local_unstable { () => () }

fn main() {
local_unstable!();
unstable_macro!(); //~ ERROR: macro unstable_macro! is unstable
}
1 change: 1 addition & 0 deletions src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
unstable_feature: None,
});
}
16 changes: 16 additions & 0 deletions src/test/run-pass/auxiliary/unstable-macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 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.

#![feature(staged_api)]
#![stable(feature = "unit_test", since = "0.0.0")]

#[unstable(feature = "unstable_macros", issue = "0")]
#[macro_export]
macro_rules! unstable_macro{ () => () }
23 changes: 23 additions & 0 deletions src/test/run-pass/macro-stability.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2018 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.

// aux-build:unstable-macros.rs

#![feature(unstable_macros)]

#[macro_use] extern crate unstable_macros;

#[unstable(feature = "local_unstable", issue = "0")]
macro_rules! local_unstable { () => () }

fn main() {
unstable_macro!();
local_unstable!();
}