Syntactically permit unsafety on mods
This commit is contained in:
parent
25b2f48612
commit
fd4dd00dde
@ -2289,12 +2289,15 @@ pub fn span(&self) -> Span {
|
|||||||
/// Module declaration.
|
/// Module declaration.
|
||||||
///
|
///
|
||||||
/// E.g., `mod foo;` or `mod foo { .. }`.
|
/// E.g., `mod foo;` or `mod foo { .. }`.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Default)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
pub struct Mod {
|
pub struct Mod {
|
||||||
/// A span from the first token past `{` to the last token until `}`.
|
/// A span from the first token past `{` to the last token until `}`.
|
||||||
/// For `mod foo;`, the inner span ranges from the first token
|
/// For `mod foo;`, the inner span ranges from the first token
|
||||||
/// to the last token in the external file.
|
/// to the last token in the external file.
|
||||||
pub inner: Span,
|
pub inner: Span,
|
||||||
|
/// `unsafe` keyword accepted syntactically for macro DSLs, but not
|
||||||
|
/// semantically by Rust.
|
||||||
|
pub unsafety: Unsafe,
|
||||||
pub items: Vec<P<Item>>,
|
pub items: Vec<P<Item>>,
|
||||||
/// `true` for `mod foo { .. }`; `false` for `mod foo;`.
|
/// `true` for `mod foo { .. }`; `false` for `mod foo;`.
|
||||||
pub inline: bool,
|
pub inline: bool,
|
||||||
@ -2302,9 +2305,12 @@ pub struct Mod {
|
|||||||
|
|
||||||
/// Foreign module declaration.
|
/// Foreign module declaration.
|
||||||
///
|
///
|
||||||
/// E.g., `extern { .. }` or `extern C { .. }`.
|
/// E.g., `extern { .. }` or `extern "C" { .. }`.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
pub struct ForeignMod {
|
pub struct ForeignMod {
|
||||||
|
/// `unsafe` keyword accepted syntactically for macro DSLs, but not
|
||||||
|
/// semantically by Rust.
|
||||||
|
pub unsafety: Unsafe,
|
||||||
pub abi: Option<StrLit>,
|
pub abi: Option<StrLit>,
|
||||||
pub items: Vec<P<ForeignItem>>,
|
pub items: Vec<P<ForeignItem>>,
|
||||||
}
|
}
|
||||||
|
@ -490,7 +490,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
|
pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
|
||||||
let ForeignMod { abi: _, items } = foreign_mod;
|
let ForeignMod { unsafety: _, abi: _, items } = foreign_mod;
|
||||||
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
|
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,7 +970,8 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
|
|||||||
vis.visit_asyncness(asyncness);
|
vis.visit_asyncness(asyncness);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn noop_visit_mod<T: MutVisitor>(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) {
|
pub fn noop_visit_mod<T: MutVisitor>(module: &mut Mod, vis: &mut T) {
|
||||||
|
let Mod { inner, unsafety: _, items, inline: _ } = module;
|
||||||
vis.visit_span(inner);
|
vis.visit_span(inner);
|
||||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||||
}
|
}
|
||||||
@ -990,7 +991,7 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
|
|||||||
|
|
||||||
let len = items.len();
|
let len = items.len();
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
let module = Mod { inner: span, items: vec![], inline: true };
|
let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true };
|
||||||
Crate { module, attrs: vec![], span, proc_macros }
|
Crate { module, attrs: vec![], span, proc_macros }
|
||||||
} else if len == 1 {
|
} else if len == 1 {
|
||||||
let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
|
let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
|
||||||
|
@ -990,12 +990,15 @@ fn visit_item(&mut self, item: &'a Item) {
|
|||||||
self.error_item_without_body(item.span, "function", msg, " { <body> }");
|
self.error_item_without_body(item.span, "function", msg, " { <body> }");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemKind::ForeignMod(_) => {
|
ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => {
|
||||||
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
||||||
self.invalid_visibility(
|
self.invalid_visibility(
|
||||||
&item.vis,
|
&item.vis,
|
||||||
Some("place qualifiers on individual foreign items instead"),
|
Some("place qualifiers on individual foreign items instead"),
|
||||||
);
|
);
|
||||||
|
if let Unsafe::Yes(span) = unsafety {
|
||||||
|
self.err_handler().span_err(span, "extern block cannot be declared unsafe");
|
||||||
|
}
|
||||||
visit::walk_item(self, item);
|
visit::walk_item(self, item);
|
||||||
self.extern_mod = old_item;
|
self.extern_mod = old_item;
|
||||||
return; // Avoid visiting again.
|
return; // Avoid visiting again.
|
||||||
@ -1029,7 +1032,10 @@ fn visit_item(&mut self, item: &'a Item) {
|
|||||||
walk_list!(self, visit_attribute, &item.attrs);
|
walk_list!(self, visit_attribute, &item.attrs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ItemKind::Mod(Mod { inline, .. }) => {
|
ItemKind::Mod(Mod { inline, unsafety, .. }) => {
|
||||||
|
if let Unsafe::Yes(span) = unsafety {
|
||||||
|
self.err_handler().span_err(span, "module cannot be declared unsafe");
|
||||||
|
}
|
||||||
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
||||||
if !inline && !self.session.contains_name(&item.attrs, sym::path) {
|
if !inline && !self.session.contains_name(&item.attrs, sym::path) {
|
||||||
self.check_mod_file_item_asciionly(item.ident);
|
self.check_mod_file_item_asciionly(item.ident);
|
||||||
|
@ -1139,7 +1139,11 @@ fn print_associated_type(
|
|||||||
self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
|
self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
|
||||||
}
|
}
|
||||||
ast::ItemKind::Mod(ref _mod) => {
|
ast::ItemKind::Mod(ref _mod) => {
|
||||||
self.head(visibility_qualified(&item.vis, "mod"));
|
self.head(to_string(|s| {
|
||||||
|
s.print_visibility(&item.vis);
|
||||||
|
s.print_unsafety(_mod.unsafety);
|
||||||
|
s.word("mod");
|
||||||
|
}));
|
||||||
self.print_ident(item.ident);
|
self.print_ident(item.ident);
|
||||||
|
|
||||||
if _mod.inline || self.is_expanded {
|
if _mod.inline || self.is_expanded {
|
||||||
@ -1154,7 +1158,10 @@ fn print_associated_type(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ItemKind::ForeignMod(ref nmod) => {
|
ast::ItemKind::ForeignMod(ref nmod) => {
|
||||||
self.head("extern");
|
self.head(to_string(|s| {
|
||||||
|
s.print_unsafety(nmod.unsafety);
|
||||||
|
s.word("extern");
|
||||||
|
}));
|
||||||
if let Some(abi) = nmod.abi {
|
if let Some(abi) = nmod.abi {
|
||||||
self.print_literal(&abi.as_lit());
|
self.print_literal(&abi.as_lit());
|
||||||
self.nbsp();
|
self.nbsp();
|
||||||
|
@ -399,7 +399,7 @@ pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
|
pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
|
||||||
let ast::ForeignMod { abi: _, items } = foreign_mod;
|
let ast::ForeignMod { unsafety: _, abi: _, items } = foreign_mod;
|
||||||
items.flat_map_in_place(|item| self.configure(item));
|
items.flat_map_in_place(|item| self.configure(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
||||||
use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path};
|
use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path};
|
||||||
use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind};
|
use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
|
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
|
||||||
use rustc_data_structures::map_in_place::MapInPlace;
|
use rustc_data_structures::map_in_place::MapInPlace;
|
||||||
@ -370,11 +370,21 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
|||||||
None => {
|
None => {
|
||||||
// Resolution failed so we return an empty expansion
|
// Resolution failed so we return an empty expansion
|
||||||
krate.attrs = vec![];
|
krate.attrs = vec![];
|
||||||
krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true };
|
krate.module = ast::Mod {
|
||||||
|
inner: orig_mod_span,
|
||||||
|
unsafety: Unsafe::No,
|
||||||
|
items: vec![],
|
||||||
|
inline: true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Some(ast::Item { span, kind, .. }) => {
|
Some(ast::Item { span, kind, .. }) => {
|
||||||
krate.attrs = vec![];
|
krate.attrs = vec![];
|
||||||
krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true };
|
krate.module = ast::Mod {
|
||||||
|
inner: orig_mod_span,
|
||||||
|
unsafety: Unsafe::No,
|
||||||
|
items: vec![],
|
||||||
|
inline: true,
|
||||||
|
};
|
||||||
self.cx.span_err(
|
self.cx.span_err(
|
||||||
span,
|
span,
|
||||||
&format!(
|
&format!(
|
||||||
@ -1441,8 +1451,15 @@ fn visit_block(&mut self, block: &mut P<Block>) {
|
|||||||
push_directory(&self.cx.sess, ident, &item.attrs, dir)
|
push_directory(&self.cx.sess, ident, &item.attrs, dir)
|
||||||
} else {
|
} else {
|
||||||
// We have an outline `mod foo;` so we need to parse the file.
|
// We have an outline `mod foo;` so we need to parse the file.
|
||||||
let (new_mod, dir) =
|
let (new_mod, dir) = parse_external_mod(
|
||||||
parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
|
&self.cx.sess,
|
||||||
|
ident,
|
||||||
|
span,
|
||||||
|
old_mod.unsafety,
|
||||||
|
dir,
|
||||||
|
&mut attrs,
|
||||||
|
pushed,
|
||||||
|
);
|
||||||
|
|
||||||
let krate = ast::Crate {
|
let krate = ast::Crate {
|
||||||
span: new_mod.inner,
|
span: new_mod.inner,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use rustc_ast::{token, Attribute, Mod};
|
use rustc_ast::{token, Attribute, Mod, Unsafe};
|
||||||
use rustc_errors::{struct_span_err, PResult};
|
use rustc_errors::{struct_span_err, PResult};
|
||||||
use rustc_parse::new_parser_from_file;
|
use rustc_parse::new_parser_from_file;
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
@ -42,6 +42,7 @@ pub struct ModulePathSuccess {
|
|||||||
sess: &Session,
|
sess: &Session,
|
||||||
id: Ident,
|
id: Ident,
|
||||||
span: Span, // The span to blame on errors.
|
span: Span, // The span to blame on errors.
|
||||||
|
unsafety: Unsafe,
|
||||||
Directory { mut ownership, path }: Directory,
|
Directory { mut ownership, path }: Directory,
|
||||||
attrs: &mut Vec<Attribute>,
|
attrs: &mut Vec<Attribute>,
|
||||||
pop_mod_stack: &mut bool,
|
pop_mod_stack: &mut bool,
|
||||||
@ -60,13 +61,16 @@ pub struct ModulePathSuccess {
|
|||||||
drop(included_mod_stack);
|
drop(included_mod_stack);
|
||||||
|
|
||||||
// Actually parse the external file as a module.
|
// Actually parse the external file as a module.
|
||||||
let mut module =
|
let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span));
|
||||||
new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?;
|
let mut module = parser.parse_mod(&token::Eof, unsafety)?;
|
||||||
module.0.inline = false;
|
module.0.inline = false;
|
||||||
module
|
module
|
||||||
};
|
};
|
||||||
// (1) ...instead, we return a dummy module.
|
// (1) ...instead, we return a dummy module.
|
||||||
let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default();
|
let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| {
|
||||||
|
let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false };
|
||||||
|
(module, Vec::new())
|
||||||
|
});
|
||||||
attrs.append(&mut new_attrs);
|
attrs.append(&mut new_attrs);
|
||||||
|
|
||||||
// Extract the directory path for submodules of `module`.
|
// Extract the directory path for submodules of `module`.
|
||||||
|
@ -28,7 +28,7 @@ impl<'a> Parser<'a> {
|
|||||||
/// Parses a source module as a crate. This is the main entry point for the parser.
|
/// Parses a source module as a crate. This is the main entry point for the parser.
|
||||||
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
|
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
let (module, attrs) = self.parse_mod(&token::Eof)?;
|
let (module, attrs) = self.parse_mod(&token::Eof, Unsafe::No)?;
|
||||||
let span = lo.to(self.token.span);
|
let span = lo.to(self.token.span);
|
||||||
let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
|
let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
|
||||||
Ok(ast::Crate { attrs, module, span, proc_macros })
|
Ok(ast::Crate { attrs, module, span, proc_macros })
|
||||||
@ -36,27 +36,38 @@ pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
|
|||||||
|
|
||||||
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
|
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
|
||||||
fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
|
fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
|
||||||
|
let unsafety = self.parse_unsafety();
|
||||||
|
self.expect_keyword(kw::Mod)?;
|
||||||
let id = self.parse_ident()?;
|
let id = self.parse_ident()?;
|
||||||
let (module, mut inner_attrs) = if self.eat(&token::Semi) {
|
let (module, mut inner_attrs) = if self.eat(&token::Semi) {
|
||||||
Default::default()
|
(Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new())
|
||||||
} else {
|
} else {
|
||||||
self.expect(&token::OpenDelim(token::Brace))?;
|
self.expect(&token::OpenDelim(token::Brace))?;
|
||||||
self.parse_mod(&token::CloseDelim(token::Brace))?
|
self.parse_mod(&token::CloseDelim(token::Brace), unsafety)?
|
||||||
};
|
};
|
||||||
attrs.append(&mut inner_attrs);
|
attrs.append(&mut inner_attrs);
|
||||||
Ok((id, ItemKind::Mod(module)))
|
Ok((id, ItemKind::Mod(module)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the contents of a module (inner attributes followed by module items).
|
/// Parses the contents of a module (inner attributes followed by module items).
|
||||||
pub fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec<Attribute>)> {
|
pub fn parse_mod(
|
||||||
|
&mut self,
|
||||||
|
term: &TokenKind,
|
||||||
|
unsafety: Unsafe,
|
||||||
|
) -> PResult<'a, (Mod, Vec<Attribute>)> {
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
let attrs = self.parse_inner_attributes()?;
|
let attrs = self.parse_inner_attributes()?;
|
||||||
let module = self.parse_mod_items(term, lo)?;
|
let module = self.parse_mod_items(term, lo, unsafety)?;
|
||||||
Ok((module, attrs))
|
Ok((module, attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a termination token, parses all of the items in a module.
|
/// Given a termination token, parses all of the items in a module.
|
||||||
fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
|
fn parse_mod_items(
|
||||||
|
&mut self,
|
||||||
|
term: &TokenKind,
|
||||||
|
inner_lo: Span,
|
||||||
|
unsafety: Unsafe,
|
||||||
|
) -> PResult<'a, Mod> {
|
||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
while let Some(item) = self.parse_item()? {
|
while let Some(item) = self.parse_item()? {
|
||||||
items.push(item);
|
items.push(item);
|
||||||
@ -75,7 +86,7 @@ fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, M
|
|||||||
|
|
||||||
let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };
|
let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };
|
||||||
|
|
||||||
Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
|
Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,8 +246,13 @@ fn parse_item_kind(
|
|||||||
self.parse_item_extern_crate()?
|
self.parse_item_extern_crate()?
|
||||||
} else {
|
} else {
|
||||||
// EXTERN BLOCK
|
// EXTERN BLOCK
|
||||||
self.parse_item_foreign_mod(attrs)?
|
self.parse_item_foreign_mod(attrs, Unsafe::No)?
|
||||||
}
|
}
|
||||||
|
} else if self.is_unsafe_foreign_mod() {
|
||||||
|
// EXTERN BLOCK
|
||||||
|
let unsafety = self.parse_unsafety();
|
||||||
|
self.expect_keyword(kw::Extern)?;
|
||||||
|
self.parse_item_foreign_mod(attrs, unsafety)?
|
||||||
} else if self.is_static_global() {
|
} else if self.is_static_global() {
|
||||||
// STATIC ITEM
|
// STATIC ITEM
|
||||||
self.bump(); // `static`
|
self.bump(); // `static`
|
||||||
@ -256,7 +272,9 @@ fn parse_item_kind(
|
|||||||
{
|
{
|
||||||
// IMPL ITEM
|
// IMPL ITEM
|
||||||
self.parse_item_impl(attrs, def())?
|
self.parse_item_impl(attrs, def())?
|
||||||
} else if self.eat_keyword(kw::Mod) {
|
} else if self.check_keyword(kw::Mod)
|
||||||
|
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod])
|
||||||
|
{
|
||||||
// MODULE ITEM
|
// MODULE ITEM
|
||||||
self.parse_item_mod(attrs)?
|
self.parse_item_mod(attrs)?
|
||||||
} else if self.eat_keyword(kw::Type) {
|
} else if self.eat_keyword(kw::Type) {
|
||||||
@ -893,10 +911,14 @@ fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> {
|
|||||||
/// extern "C" {}
|
/// extern "C" {}
|
||||||
/// extern {}
|
/// extern {}
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_item_foreign_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
|
fn parse_item_foreign_mod(
|
||||||
|
&mut self,
|
||||||
|
attrs: &mut Vec<Attribute>,
|
||||||
|
unsafety: Unsafe,
|
||||||
|
) -> PResult<'a, ItemInfo> {
|
||||||
let abi = self.parse_abi(); // ABI?
|
let abi = self.parse_abi(); // ABI?
|
||||||
let items = self.parse_item_list(attrs, |p| p.parse_foreign_item())?;
|
let items = self.parse_item_list(attrs, |p| p.parse_foreign_item())?;
|
||||||
let module = ast::ForeignMod { abi, items };
|
let module = ast::ForeignMod { unsafety, abi, items };
|
||||||
Ok((Ident::invalid(), ItemKind::ForeignMod(module)))
|
Ok((Ident::invalid(), ItemKind::ForeignMod(module)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,6 +960,15 @@ fn error_on_foreign_const(&self, span: Span, ident: Ident) {
|
|||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_unsafe_foreign_mod(&self) -> bool {
|
||||||
|
self.token.is_keyword(kw::Unsafe)
|
||||||
|
&& self.is_keyword_ahead(1, &[kw::Extern])
|
||||||
|
&& self.look_ahead(
|
||||||
|
2 + self.look_ahead(2, |t| t.can_begin_literal_maybe_minus() as usize),
|
||||||
|
|t| t.kind == token::OpenDelim(token::Brace),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn is_static_global(&mut self) -> bool {
|
fn is_static_global(&mut self) -> bool {
|
||||||
if self.check_keyword(kw::Static) {
|
if self.check_keyword(kw::Static) {
|
||||||
// Check if this could be a closure.
|
// Check if this could be a closure.
|
||||||
@ -1552,10 +1583,14 @@ pub(super) fn check_fn_front_matter(&mut self) -> bool {
|
|||||||
// `$qual fn` or `$qual $qual`:
|
// `$qual fn` or `$qual $qual`:
|
||||||
|| QUALS.iter().any(|&kw| self.check_keyword(kw))
|
|| QUALS.iter().any(|&kw| self.check_keyword(kw))
|
||||||
&& self.look_ahead(1, |t| {
|
&& self.look_ahead(1, |t| {
|
||||||
// ...qualified and then `fn`, e.g. `const fn`.
|
// `$qual fn`, e.g. `const fn` or `async fn`.
|
||||||
t.is_keyword(kw::Fn)
|
t.is_keyword(kw::Fn)
|
||||||
// Two qualifiers. This is enough. Due `async` we need to check that it's reserved.
|
// Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`.
|
||||||
|| t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) && i.is_reserved())
|
|| t.is_non_raw_ident_where(|i| QUALS.contains(&i.name)
|
||||||
|
// Rule out 2015 `const async: T = val`.
|
||||||
|
&& i.is_reserved()
|
||||||
|
// Rule out unsafe extern block.
|
||||||
|
&& !self.is_unsafe_foreign_mod())
|
||||||
})
|
})
|
||||||
// `extern ABI fn`
|
// `extern ABI fn`
|
||||||
|| self.check_keyword(kw::Extern)
|
|| self.check_keyword(kw::Extern)
|
||||||
@ -1567,9 +1602,9 @@ pub(super) fn check_fn_front_matter(&mut self) -> bool {
|
|||||||
/// up to and including the `fn` keyword. The formal grammar is:
|
/// up to and including the `fn` keyword. The formal grammar is:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// Extern = "extern" StringLit ;
|
/// Extern = "extern" StringLit? ;
|
||||||
/// FnQual = "const"? "async"? "unsafe"? Extern? ;
|
/// FnQual = "const"? "async"? "unsafe"? Extern? ;
|
||||||
/// FnFrontMatter = FnQual? "fn" ;
|
/// FnFrontMatter = FnQual "fn" ;
|
||||||
/// ```
|
/// ```
|
||||||
pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
|
pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
|
||||||
let constness = self.parse_constness();
|
let constness = self.parse_constness();
|
||||||
|
@ -1 +1 @@
|
|||||||
{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
|
{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
|
||||||
|
@ -1 +1 @@
|
|||||||
{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
|
{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
|
||||||
|
9
src/test/ui/parser/unsafe-foreign-mod.rs
Normal file
9
src/test/ui/parser/unsafe-foreign-mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
unsafe extern {
|
||||||
|
//~^ ERROR extern block cannot be declared unsafe
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" {
|
||||||
|
//~^ ERROR extern block cannot be declared unsafe
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
src/test/ui/parser/unsafe-foreign-mod.stderr
Normal file
14
src/test/ui/parser/unsafe-foreign-mod.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error: extern block cannot be declared unsafe
|
||||||
|
--> $DIR/unsafe-foreign-mod.rs:1:1
|
||||||
|
|
|
||||||
|
LL | unsafe extern {
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: extern block cannot be declared unsafe
|
||||||
|
--> $DIR/unsafe-foreign-mod.rs:5:1
|
||||||
|
|
|
||||||
|
LL | unsafe extern "C" {
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
9
src/test/ui/parser/unsafe-mod.rs
Normal file
9
src/test/ui/parser/unsafe-mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
unsafe mod m {
|
||||||
|
//~^ ERROR module cannot be declared unsafe
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe mod n;
|
||||||
|
//~^ ERROR module cannot be declared unsafe
|
||||||
|
//~^^ ERROR file not found for module `n`
|
||||||
|
|
||||||
|
fn main() {}
|
23
src/test/ui/parser/unsafe-mod.stderr
Normal file
23
src/test/ui/parser/unsafe-mod.stderr
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
error[E0583]: file not found for module `n`
|
||||||
|
--> $DIR/unsafe-mod.rs:5:1
|
||||||
|
|
|
||||||
|
LL | unsafe mod n;
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: to create the module `n`, create file "$DIR/n.rs"
|
||||||
|
|
||||||
|
error: module cannot be declared unsafe
|
||||||
|
--> $DIR/unsafe-mod.rs:1:1
|
||||||
|
|
|
||||||
|
LL | unsafe mod m {
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: module cannot be declared unsafe
|
||||||
|
--> $DIR/unsafe-mod.rs:5:1
|
||||||
|
|
|
||||||
|
LL | unsafe mod n;
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0583`.
|
89
src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs
Normal file
89
src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// force-host
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
// These are tests for syntax that is accepted by the Rust parser but
|
||||||
|
// unconditionally rejected semantically after macro expansion. Attribute macros
|
||||||
|
// are permitted to accept such syntax as long as they replace it with something
|
||||||
|
// that makes sense to Rust.
|
||||||
|
//
|
||||||
|
// We also inspect some of the spans to verify the syntax is not triggering the
|
||||||
|
// lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081).
|
||||||
|
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
#![feature(proc_macro_span)]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree};
|
||||||
|
use std::path::Component;
|
||||||
|
|
||||||
|
// unsafe mod m {
|
||||||
|
// pub unsafe mod inner;
|
||||||
|
// }
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
let tokens = &mut input.into_iter();
|
||||||
|
expect(tokens, "unsafe");
|
||||||
|
expect(tokens, "mod");
|
||||||
|
expect(tokens, "m");
|
||||||
|
let tokens = &mut expect_brace(tokens);
|
||||||
|
expect(tokens, "pub");
|
||||||
|
expect(tokens, "unsafe");
|
||||||
|
expect(tokens, "mod");
|
||||||
|
let ident = expect(tokens, "inner");
|
||||||
|
expect(tokens, ";");
|
||||||
|
check_useful_span(ident, "unsafe-mod.rs");
|
||||||
|
TokenStream::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafe extern {
|
||||||
|
// type T;
|
||||||
|
// }
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
let tokens = &mut input.into_iter();
|
||||||
|
expect(tokens, "unsafe");
|
||||||
|
expect(tokens, "extern");
|
||||||
|
let tokens = &mut expect_brace(tokens);
|
||||||
|
expect(tokens, "type");
|
||||||
|
let ident = expect(tokens, "T");
|
||||||
|
expect(tokens, ";");
|
||||||
|
check_useful_span(ident, "unsafe-foreign-mod.rs");
|
||||||
|
TokenStream::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafe extern "C++" {}
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
let tokens = &mut input.into_iter();
|
||||||
|
expect(tokens, "unsafe");
|
||||||
|
expect(tokens, "extern");
|
||||||
|
let abi = expect(tokens, "\"C++\"");
|
||||||
|
expect_brace(tokens);
|
||||||
|
check_useful_span(abi, "unsafe-foreign-mod.rs");
|
||||||
|
TokenStream::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree {
|
||||||
|
match tokens.next() {
|
||||||
|
Some(token) if token.to_string() == expected => token,
|
||||||
|
wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter {
|
||||||
|
match tokens.next() {
|
||||||
|
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => {
|
||||||
|
group.stream().into_iter()
|
||||||
|
}
|
||||||
|
wrong => panic!("unexpected token: {:?}, expected `{{`", wrong),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_useful_span(token: TokenTree, expected_filename: &str) {
|
||||||
|
let span = token.span();
|
||||||
|
assert!(span.start().column < span.end().column);
|
||||||
|
|
||||||
|
let source_path = span.source_file().path();
|
||||||
|
let filename = source_path.components().last().unwrap();
|
||||||
|
assert_eq!(filename, Component::Normal(expected_filename.as_ref()));
|
||||||
|
}
|
14
src/test/ui/proc-macro/unsafe-foreign-mod.rs
Normal file
14
src/test/ui/proc-macro/unsafe-foreign-mod.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// run-pass
|
||||||
|
// aux-build:macro-only-syntax.rs
|
||||||
|
|
||||||
|
extern crate macro_only_syntax;
|
||||||
|
|
||||||
|
#[macro_only_syntax::expect_unsafe_foreign_mod]
|
||||||
|
unsafe extern {
|
||||||
|
type T;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_only_syntax::expect_unsafe_extern_cpp_mod]
|
||||||
|
unsafe extern "C++" {}
|
||||||
|
|
||||||
|
fn main() {}
|
13
src/test/ui/proc-macro/unsafe-mod.rs
Normal file
13
src/test/ui/proc-macro/unsafe-mod.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// run-pass
|
||||||
|
// aux-build:macro-only-syntax.rs
|
||||||
|
|
||||||
|
#![feature(proc_macro_hygiene)]
|
||||||
|
|
||||||
|
extern crate macro_only_syntax;
|
||||||
|
|
||||||
|
#[macro_only_syntax::expect_unsafe_mod]
|
||||||
|
unsafe mod m {
|
||||||
|
pub unsafe mod inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user