Skip to content

check stability of macro invocations #48524

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

Merged
merged 1 commit into from
Mar 16, 2018
Merged
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
@@ -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) => {
@@ -149,6 +151,7 @@ impl<'a> Registry<'a> {
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
unstable_feature: None,
});
}

4 changes: 4 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
@@ -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
@@ -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;
@@ -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(),
}
56 changes: 40 additions & 16 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
@@ -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};
@@ -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;

@@ -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,
@@ -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()))
}
@@ -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()))
}
13 changes: 12 additions & 1 deletion src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
@@ -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)))
2 changes: 2 additions & 0 deletions src/libsyntax_ext/lib.rs
Original file line number Diff line number Diff line change
@@ -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,
});
)* }
}
@@ -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 {
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
@@ -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!();
}