resolve: Implement prelude search for macro paths

resolve/expansion: Implement tool attributes
This commit is contained in:
Vadim Petrochenkov 2018-07-23 02:52:51 +03:00
parent c63bb1d6a7
commit c3e54217e8
42 changed files with 683 additions and 143 deletions

View File

@ -49,6 +49,7 @@ pub enum Def {
PrimTy(hir::PrimTy),
TyParam(DefId),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
ToolMod, // e.g. `rustfmt` in `#[rustfmt::skip]`
// Value namespace
Fn(DefId),
@ -67,6 +68,7 @@ pub enum Def {
// Macro namespace
Macro(DefId, MacroKind),
NonMacroAttr, // e.g. `#[inline]` or `#[rustfmt::skip]`
GlobalAsm(DefId),
@ -259,6 +261,8 @@ impl Def {
Def::Label(..) |
Def::PrimTy(..) |
Def::SelfTy(..) |
Def::ToolMod |
Def::NonMacroAttr |
Def::Err => {
bug!("attempted .def_id() on invalid def: {:?}", self)
}
@ -299,6 +303,8 @@ impl Def {
Def::SelfTy(..) => "self type",
Def::Macro(.., macro_kind) => macro_kind.descr(),
Def::GlobalAsm(..) => "global asm",
Def::ToolMod => "tool module",
Def::NonMacroAttr => "non-macro attribute",
Def::Err => "unresolved item",
}
}

View File

@ -1016,6 +1016,8 @@ impl_stable_hash_for!(enum hir::def::Def {
Label(node_id),
Macro(def_id, macro_kind),
GlobalAsm(def_id),
ToolMod,
NonMacroAttr,
Err
});

View File

@ -629,7 +629,8 @@ impl<'a> Resolver<'a> {
pub fn get_macro(&mut self, def: Def) -> Lrc<SyntaxExtension> {
let def_id = match def {
Def::Macro(def_id, ..) => def_id,
_ => panic!("Expected Def::Macro(..)"),
Def::NonMacroAttr => return Lrc::new(SyntaxExtension::NonMacroAttr),
_ => panic!("Expected Def::Macro(..) or Def::NonMacroAttr"),
};
if let Some(ext) = self.macro_map.get(&def_id) {
return ext.clone();

View File

@ -131,8 +131,7 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
directive.vis.get() == ty::Visibility::Public ||
directive.span.is_dummy() => {
if let ImportDirectiveSubclass::MacroUse = directive.subclass {
if resolver.session.features_untracked().use_extern_macros &&
!directive.span.is_dummy() {
if resolver.use_extern_macros && !directive.span.is_dummy() {
resolver.session.buffer_lint(
lint::builtin::MACRO_USE_EXTERN_CRATE,
directive.id,

View File

@ -86,6 +86,10 @@ mod check_unused;
mod build_reduced_graph;
mod resolve_imports;
fn is_known_tool(name: Name) -> bool {
["clippy", "rustfmt"].contains(&&*name.as_str())
}
/// A free importable items suggested in case of resolution failure.
struct ImportSuggestion {
path: Path,
@ -200,16 +204,11 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
err.span_label(typaram_span, "type variable from outer function");
}
},
Def::Mod(..) | Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Variant(..) |
Def::Trait(..) | Def::TyAlias(..) | Def::TyForeign(..) | Def::TraitAlias(..) |
Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) |
Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) |
Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) |
Def::Existential(..) | Def::AssociatedExistential(..) |
Def::Macro(..) | Def::GlobalAsm(..) | Def::Err =>
_ => {
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
Def::TyParam")
}
}
// Try to retrieve the span of the function signature and generate a new message with
// a local type parameter
@ -1711,9 +1710,7 @@ impl<'a> Resolver<'a> {
vis: ty::Visibility::Public,
}),
// The `proc_macro` and `decl_macro` features imply `use_extern_macros`
use_extern_macros:
features.use_extern_macros || features.decl_macro,
use_extern_macros: features.use_extern_macros(),
crate_loader,
macro_names: FxHashSet(),
@ -1846,6 +1843,7 @@ impl<'a> Resolver<'a> {
path_span: Span)
-> Option<LexicalScopeBinding<'a>> {
let record_used = record_used_id.is_some();
assert!(ns == TypeNS || ns == ValueNS);
if ns == TypeNS {
ident.span = if ident.name == keywords::SelfType.name() {
// FIXME(jseyfried) improve `Self` hygiene
@ -1922,8 +1920,9 @@ impl<'a> Resolver<'a> {
return Some(LexicalScopeBinding::Item(binding))
}
_ if poisoned.is_some() => break,
Err(Undetermined) => return None,
Err(Determined) => {}
Err(Determined) => continue,
Err(Undetermined) =>
span_bug!(ident.span, "undetermined resolution during main resolution pass"),
}
}
@ -1945,6 +1944,11 @@ impl<'a> Resolver<'a> {
ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding));
}
if ns == TypeNS && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding));
}
if let Some(prelude) = self.prelude {
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
false, false, path_span) {
@ -3505,6 +3509,8 @@ impl<'a> Resolver<'a> {
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
if let Some(next_module) = binding.module() {
module = Some(next_module);
} else if def == Def::ToolMod && i + 1 != path.len() {
return PathResult::NonModule(PathResolution::new(Def::NonMacroAttr))
} else if def == Def::Err {
return PathResult::NonModule(err_path_resolution());
} else if opt_ns.is_some() && (is_last || maybe_assoc) {

View File

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use {AmbiguityError, CrateLint, Resolver, ResolutionError, resolve_error};
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult};
use Namespace::{self, MacroNS};
use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
use Namespace::{self, TypeNS, MacroNS};
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
use resolve_imports::ImportResolver;
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
@ -27,7 +27,7 @@ use syntax::ext::expand::{self, AstFragment, AstFragmentKind, Invocation, Invoca
use syntax::ext::hygiene::{self, Mark};
use syntax::ext::placeholders::placeholder;
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue};
use syntax::fold::{self, Folder};
use syntax::parse::parser::PathStyle;
use syntax::parse::token::{self, Token};
@ -326,6 +326,18 @@ impl<'a> base::Resolver for Resolver<'a> {
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
self.report_proc_macro_stub(invoc.span());
return Err(Determinacy::Determined);
} else if let Def::NonMacroAttr = def {
if let InvocationKind::Attr { .. } = invoc.kind {
if !self.session.features_untracked().tool_attributes {
feature_err(&self.session.parse_sess, "tool_attributes",
invoc.span(), GateIssue::Language,
"tool attributes are unstable").emit();
}
return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr)));
} else {
self.report_non_macro_attr(invoc.path_span());
return Err(Determinacy::Determined);
}
}
let def_id = def.def_id();
@ -348,6 +360,9 @@ impl<'a> base::Resolver for Resolver<'a> {
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
self.report_proc_macro_stub(path.span);
return Err(Determinacy::Determined);
} else if let Def::NonMacroAttr = def {
self.report_non_macro_attr(path.span);
return Err(Determinacy::Determined);
}
self.unused_macros.remove(&def.def_id());
Ok(self.get_macro(def))
@ -378,6 +393,11 @@ impl<'a> Resolver<'a> {
"can't use a procedural macro from the same crate that defines it");
}
fn report_non_macro_attr(&self, span: Span) {
self.session.span_err(span,
"expected a macro, found non-macro attribute");
}
fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
-> Result<Def, Determinacy> {
let (attr, traits, item) = match invoc.kind {
@ -450,7 +470,15 @@ impl<'a> Resolver<'a> {
fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-> Result<Def, Determinacy> {
if kind != MacroKind::Bang && path.segments.len() > 1 {
let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
if def != Err(Determinacy::Undetermined) {
// Do not report duplicated errors on every undetermined resolution.
path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
self.session.span_err(segment.args.as_ref().unwrap().span(),
"generic arguments in macro path");
});
}
if kind != MacroKind::Bang && path.segments.len() > 1 && def != Ok(Def::NonMacroAttr) {
if !self.session.features_untracked().proc_macro_path_invoc {
emit_feature_err(
&self.session.parse_sess,
@ -462,15 +490,6 @@ impl<'a> Resolver<'a> {
);
}
}
let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
if def != Err(Determinacy::Undetermined) {
// Do not report duplicated errors on every undetermined resolution.
path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
self.session.span_err(segment.args.as_ref().unwrap().span(),
"generic arguments in macro path");
});
}
def
}
@ -544,67 +563,226 @@ impl<'a> Resolver<'a> {
result
}
// Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`)
// Resolve the initial segment of a non-global macro path
// (e.g. `foo` in `foo::bar!(); or `foo!();`).
// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
// expansion and import resolution (perhaps they can be merged in the future).
pub fn resolve_lexical_macro_path_segment(&mut self,
mut ident: Ident,
ns: Namespace,
record_used: bool,
path_span: Span)
-> Result<MacroBinding<'a>, Determinacy> {
ident = ident.modern();
let mut module = Some(self.current_module);
let mut potential_illegal_shadower = Err(Determinacy::Determined);
let determinacy =
if record_used { Determinacy::Determined } else { Determinacy::Undetermined };
loop {
let orig_current_module = self.current_module;
let result = if let Some(module) = module {
self.current_module = module; // Lexical resolutions can never be a privacy error.
// Since expanded macros may not shadow the lexical scope and
// globs may not shadow global macros (both enforced below),
// we resolve with restricted shadowing (indicated by the penultimate argument).
self.resolve_ident_in_module_unadjusted(
module, ident, ns, true, record_used, path_span,
).map(MacroBinding::Modern)
} else {
self.macro_prelude.get(&ident.name).cloned().ok_or(determinacy)
.map(MacroBinding::Global)
};
self.current_module = orig_current_module;
// General principles:
// 1. Not controlled (user-defined) names should have higher priority than controlled names
// built into the language or standard library. This way we can add new names into the
// language or standard library without breaking user code.
// 2. "Closed set" below means new names can appear after the current resolution attempt.
// Places to search (in order of decreasing priority):
// (Type NS)
// 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
// (open set, not controlled).
// 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
// (open, not controlled).
// 3. Extern prelude (closed, not controlled).
// 4. Tool modules (closed, controlled right now, but not in the future).
// 5. Standard library prelude (de-facto closed, controlled).
// 6. Language prelude (closed, controlled).
// (Macro NS)
// 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
// (open, not controlled).
// 2. Macro prelude (language, standard library, user-defined legacy plugins lumped into
// one set) (open, the open part is from macro expansions, not controlled).
// 2a. User-defined prelude from macro-use
// (open, the open part is from macro expansions, not controlled).
// 2b. Standard library prelude, currently just a macro-use (closed, controlled)
// 2c. Language prelude, perhaps including builtin attributes
// (closed, controlled, except for legacy plugins).
// 3. Builtin attributes (closed, controlled).
match result.map(MacroBinding::binding) {
Ok(binding) => {
if !record_used {
return result;
assert!(ns == TypeNS || ns == MacroNS);
ident = ident.modern();
// Names from inner scope that can't shadow names from outer scopes, e.g.
// mod m { ... }
// {
// use prefix::*; // if this imports another `m`, then it can't shadow the outer `m`
// // and we have and ambiguity error
// m::mac!();
// }
// This includes names from globs and from macro expansions.
let mut potentially_ambiguous_result: Option<MacroBinding> = None;
enum WhereToResolve<'a> {
Module(Module<'a>),
MacroPrelude,
BuiltinAttrs,
ExternPrelude,
ToolPrelude,
StdLibPrelude,
PrimitiveTypes,
}
if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower {
if shadower.def() != binding.def() {
let name = ident.name;
// Go through all the scopes and try to resolve the name.
let mut where_to_resolve = WhereToResolve::Module(self.current_module);
let mut use_prelude = !self.current_module.no_implicit_prelude;
loop {
let result = match where_to_resolve {
WhereToResolve::Module(module) => {
let orig_current_module = mem::replace(&mut self.current_module, module);
let binding = self.resolve_ident_in_module_unadjusted(
module, ident, ns, true, record_used, path_span,
);
self.current_module = orig_current_module;
binding.map(MacroBinding::Modern)
}
WhereToResolve::MacroPrelude => {
match self.macro_prelude.get(&ident.name).cloned() {
Some(binding) => Ok(MacroBinding::Global(binding)),
None => Err(Determinacy::Determined),
}
}
WhereToResolve::BuiltinAttrs => {
if is_builtin_attr_name(ident.name) {
let binding = (Def::NonMacroAttr, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok(MacroBinding::Global(binding))
} else {
Err(Determinacy::Determined)
}
}
WhereToResolve::ExternPrelude => {
if use_prelude && self.extern_prelude.contains(&ident.name) {
if !self.session.features_untracked().extern_prelude &&
!self.ignore_extern_prelude_feature {
feature_err(&self.session.parse_sess, "extern_prelude",
ident.span, GateIssue::Language,
"access to extern crates through prelude is experimental")
.emit();
}
let crate_id =
self.crate_loader.process_path_extern(ident.name, ident.span);
let crate_root =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(crate_root);
let binding = (crate_root, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok(MacroBinding::Global(binding))
} else {
Err(Determinacy::Determined)
}
}
WhereToResolve::ToolPrelude => {
if use_prelude && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok(MacroBinding::Global(binding))
} else {
Err(Determinacy::Determined)
}
}
WhereToResolve::StdLibPrelude => {
let mut result = Err(Determinacy::Determined);
if use_prelude {
if let Some(prelude) = self.prelude {
if let Ok(binding) =
self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
false, false, path_span) {
result = Ok(MacroBinding::Global(binding));
}
}
}
result
}
WhereToResolve::PrimitiveTypes => {
if let Some(prim_ty) =
self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok(MacroBinding::Global(binding))
} else {
Err(Determinacy::Determined)
}
}
};
macro_rules! continue_search { () => {
where_to_resolve = match where_to_resolve {
WhereToResolve::Module(module) => {
match self.hygienic_lexical_parent(module, &mut ident.span) {
Some(parent_module) => WhereToResolve::Module(parent_module),
None => {
use_prelude = !module.no_implicit_prelude;
if ns == MacroNS {
WhereToResolve::MacroPrelude
} else {
WhereToResolve::ExternPrelude
}
}
}
}
WhereToResolve::MacroPrelude => WhereToResolve::BuiltinAttrs,
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
WhereToResolve::StdLibPrelude => WhereToResolve::PrimitiveTypes,
WhereToResolve::PrimitiveTypes => break, // nowhere else to search
};
continue;
}}
match result {
Ok(result) => {
if !record_used {
return Ok(result);
}
let binding = result.binding();
// Found a solution that is ambiguous with a previously found solution.
// Push an ambiguity error for later reporting and
// return something for better recovery.
if let Some(previous_result) = potentially_ambiguous_result {
if binding.def() != previous_result.binding().def() {
self.ambiguity_errors.push(AmbiguityError {
span: path_span,
name,
b1: shadower,
name: ident.name,
b1: previous_result.binding(),
b2: binding,
lexical: true,
});
return potential_illegal_shadower;
return Ok(previous_result);
}
}
if binding.is_glob_import() || binding.expansion != Mark::root() {
potential_illegal_shadower = result;
} else {
return result;
}
},
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
Err(Determinacy::Determined) => {}
}
module = match module {
Some(module) => self.hygienic_lexical_parent(module, &mut ident.span),
None => return potential_illegal_shadower,
// Found a solution that's not an ambiguity yet, but is "suspicious" and
// can participate in ambiguities later on.
// Remember it and go search for other solutions in outer scopes.
if binding.is_glob_import() || binding.expansion != Mark::root() {
potentially_ambiguous_result = Some(result);
continue_search!();
}
// Found a solution that can't be ambiguous, great success.
return Ok(result);
},
Err(Determinacy::Determined) => {
continue_search!();
}
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
}
}
// Previously found potentially ambiguous result turned out to not be ambiguous after all.
if let Some(previous_result) = potentially_ambiguous_result {
return Ok(previous_result);
}
if record_used { Err(Determinacy::Determined) } else { Err(Determinacy::Undetermined) }
}
pub fn resolve_legacy_scope(&mut self,

View File

@ -811,6 +811,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
HirDef::Label(..) |
HirDef::Macro(..) |
HirDef::GlobalAsm(..) |
HirDef::ToolMod |
HirDef::NonMacroAttr |
HirDef::Err => None,
}
}

View File

@ -89,17 +89,8 @@ pub fn is_known(attr: &Attribute) -> bool {
})
}
const RUST_KNOWN_TOOL: &[&str] = &["clippy", "rustfmt"];
const RUST_KNOWN_LINT_TOOL: &[&str] = &["clippy"];
pub fn is_known_tool(attr: &Attribute) -> bool {
let tool_name =
attr.path.segments.iter().next().expect("empty path in attribute").ident.name;
RUST_KNOWN_TOOL.contains(&tool_name.as_str().as_ref())
}
pub fn is_known_lint_tool(m_item: Ident) -> bool {
RUST_KNOWN_LINT_TOOL.contains(&m_item.as_str().as_ref())
["clippy"].contains(&m_item.as_str().as_ref())
}
impl NestedMetaItem {
@ -245,10 +236,6 @@ impl Attribute {
pub fn is_value_str(&self) -> bool {
self.value_str().is_some()
}
pub fn is_scoped(&self) -> bool {
self.path.segments.len() > 1
}
}
impl MetaItem {

View File

@ -588,6 +588,9 @@ impl MacroKind {
/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
/// A trivial "extension" that does nothing, only keeps the attribute and marks it as known.
NonMacroAttr,
/// A syntax extension that is attached to an item and creates new items
/// based upon it.
///
@ -667,6 +670,7 @@ impl SyntaxExtension {
SyntaxExtension::IdentTT(..) |
SyntaxExtension::ProcMacro { .. } =>
MacroKind::Bang,
SyntaxExtension::NonMacroAttr |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |
SyntaxExtension::AttrProcMacro(..) =>
@ -696,6 +700,7 @@ impl SyntaxExtension {
SyntaxExtension::AttrProcMacro(.., edition) |
SyntaxExtension::ProcMacroDerive(.., edition) => edition,
// Unstable legacy stuff
SyntaxExtension::NonMacroAttr |
SyntaxExtension::IdentTT(..) |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |

View File

@ -36,7 +36,7 @@ use visit::{self, Visitor};
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::{iter, mem};
use std::rc::Rc;
use std::path::PathBuf;
@ -243,6 +243,15 @@ impl Invocation {
}
}
pub fn path_span(&self) -> Span {
match self.kind {
InvocationKind::Bang { ref mac, .. } => mac.node.path.span,
InvocationKind::Attr { attr: Some(ref attr), .. } => attr.path.span,
InvocationKind::Attr { attr: None, .. } => DUMMY_SP,
InvocationKind::Derive { ref path, .. } => path.span,
}
}
pub fn attr_id(&self) -> Option<ast::AttrId> {
match self.kind {
InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id),
@ -566,6 +575,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
});
match *ext {
NonMacroAttr => {
attr::mark_known(&attr);
let item = item.map_attrs(|mut attrs| { attrs.push(attr); attrs });
Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
}
MultiModifier(ref mac) => {
let meta = attr.parse_meta(self.cx.parse_sess)
.map_err(|mut e| { e.emit(); }).ok()?;
@ -810,7 +824,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}
MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
MultiDecorator(..) | MultiModifier(..) |
AttrProcMacro(..) | SyntaxExtension::NonMacroAttr => {
self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path));
self.cx.trace_macros_diag();
@ -1612,13 +1627,16 @@ impl<'feat> ExpansionConfig<'feat> {
fn enable_allow_internal_unstable = allow_internal_unstable,
fn enable_custom_derive = custom_derive,
fn enable_format_args_nl = format_args_nl,
fn use_extern_macros_enabled = use_extern_macros,
fn macros_in_extern_enabled = macros_in_extern,
fn proc_macro_mod = proc_macro_mod,
fn proc_macro_gen = proc_macro_gen,
fn proc_macro_expr = proc_macro_expr,
fn proc_macro_non_items = proc_macro_non_items,
}
pub fn use_extern_macros_enabled(&self) -> bool {
self.features.map_or(false, |features| features.use_extern_macros())
}
}
// A Marker adds the given mark to the syntax context.

View File

@ -80,6 +80,11 @@ macro_rules! declare_features {
{
$(f(stringify!($feature), self.$feature);)+
}
pub fn use_extern_macros(&self) -> bool {
// The `decl_macro` and `tool_attributes` features imply `use_extern_macros`.
self.use_extern_macros || self.decl_macro || self.tool_attributes
}
}
};
@ -689,6 +694,10 @@ pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, Att
BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
}
pub fn is_builtin_attr_name(name: ast::Name) -> bool {
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| name == builtin_name)
}
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) ||
attr.name().as_str().starts_with("rustc_")
@ -1198,28 +1207,9 @@ impl<'a> Context<'a> {
// before the plugin attributes are registered
// so we skip this then
if !is_macro {
if attr.is_scoped() {
gate_feature!(self, tool_attributes, attr.span,
&format!("scoped attribute `{}` is experimental", attr.path));
if attr::is_known_tool(attr) {
attr::mark_used(attr);
} else {
span_err!(
self.parse_sess.span_diagnostic,
attr.span,
E0694,
"an unknown tool name found in scoped attribute: `{}`.",
attr.path
);
}
} else {
gate_feature!(self, custom_attribute, attr.span,
&format!("The attribute `{}` is currently \
unknown to the compiler and \
may have meaning \
added to it in the future",
attr.path));
}
let msg = format!("The attribute `{}` is currently unknown to the compiler and \
may have meaning added to it in the future", attr.path);
gate_feature!(self, custom_attribute, attr.span, &msg);
}
}
}
@ -1529,7 +1519,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
if self.context.features.use_extern_macros && attr::is_known(attr) {
if self.context.features.use_extern_macros() && attr::is_known(attr) {
return
}
@ -2004,7 +1994,7 @@ impl FeatureChecker {
// the branching can be eliminated by modifying `set!()` to set these spans
// only for the features that need to be checked for mutual exclusion.
fn collect(&mut self, features: &Features, span: Span) {
if features.use_extern_macros {
if features.use_extern_macros() {
// If self.use_extern_macros is None, set to Some(span)
self.use_extern_macros = self.use_extern_macros.or(Some(span));
}

View File

@ -8,9 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(tool_attributes)]
#![feature(use_extern_macros, proc_macro_path_invoc)]
#![foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
#[foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
#[foo::bar] //~ ERROR failed to resolve. Use of undeclared type or module `foo`
fn main() {}

View File

@ -11,7 +11,7 @@
// aux-build:issue-42708.rs
// ignore-stage1
#![feature(decl_macro, use_extern_macros, proc_macro_path_invoc)]
#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
extern crate issue_42708;

View File

@ -11,7 +11,7 @@
// aux-build:issue-50061.rs
// ignore-stage1
#![feature(use_extern_macros, proc_macro_path_invoc, decl_macro)]
#![feature(proc_macro_path_invoc, decl_macro)]
extern crate issue_50061;

View File

@ -11,7 +11,7 @@
// aux-build:parent-source-spans.rs
// ignore-stage1
#![feature(use_extern_macros, decl_macro, proc_macro_non_items)]
#![feature(decl_macro, proc_macro_non_items)]
extern crate parent_source_spans;

View File

@ -12,3 +12,8 @@
macro_rules! mac {
($ident:ident) => { let $ident = 42; }
}
#[macro_export]
macro_rules! inline {
() => ()
}

View File

@ -1,4 +1,4 @@
error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:29:5
|
LL | returns_isize!(rust_get_test_int);
@ -6,7 +6,7 @@ LL | returns_isize!(rust_get_test_int);
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:31:5
|
LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
@ -14,7 +14,7 @@ LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:33:5
|
LL | emits_nothing!();

View File

@ -8,8 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(use_extern_macros)]
fn main() {
#[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
#[rustfmt::skip] //~ ERROR tool attributes are unstable
let x = 3
;
}

View File

@ -1,7 +1,7 @@
error[E0658]: scoped attribute `rustfmt::skip` is experimental (see issue #44690)
--> $DIR/feature-gate-tool_attributes.rs:12:5
error[E0658]: tool attributes are unstable (see issue #44690)
--> $DIR/feature-gate-tool_attributes.rs:14:5
|
LL | #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
LL | #[rustfmt::skip] //~ ERROR tool attributes are unstable
| ^^^^^^^^^^^^^^^^
|
= help: add #![feature(tool_attributes)] to the crate attributes to enable

View File

@ -9,6 +9,6 @@
// except according to those terms.
fn main() {
print!(test!());
print!(testo!());
//~^ ERROR: format argument must be a string literal
}

View File

@ -1,11 +1,11 @@
error: format argument must be a string literal
--> $DIR/issue-11692-1.rs:12:12
|
LL | print!(test!());
| ^^^^^^^
LL | print!(testo!());
| ^^^^^^^^
help: you might be missing a string literal to format with
|
LL | print!("{}", test!());
LL | print!("{}", testo!());
| ^^^^^
error: aborting due to previous error

View File

@ -10,5 +10,5 @@
fn main() {
concat!(test!());
//~^ ERROR cannot find macro `test!` in this scope
//~^ ERROR expected a macro, found non-macro attribute
}

View File

@ -1,4 +1,4 @@
error: cannot find macro `test!` in this scope
error: expected a macro, found non-macro attribute
--> $DIR/issue-11692-2.rs:12:13
|
LL | concat!(test!());

View File

@ -10,7 +10,7 @@
// compile-pass
#![feature(use_extern_macros, decl_macro)]
#![feature(decl_macro)]
mod type_ns {
pub type A = u8;

View File

@ -8,11 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Make sure that 'custom_attributes' feature does not allow scoped attributes.
#![feature(use_extern_macros, extern_prelude)]
#![feature(custom_attributes)]
mod m {
fn check() {
Vec::clone!(); //~ ERROR failed to resolve. Not a module `Vec`
u8::clone!(); //~ ERROR failed to resolve. Not a module `u8`
}
}
#[foo::bar]
//~^ ERROR scoped attribute `foo::bar` is experimental (see issue #44690) [E0658]
//~^^ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0433]: failed to resolve. Not a module `Vec`
--> $DIR/macro-path-prelude-fail-1.rs:15:9
|
LL | Vec::clone!(); //~ ERROR failed to resolve. Not a module `Vec`
| ^^^ Not a module `Vec`
error[E0433]: failed to resolve. Not a module `u8`
--> $DIR/macro-path-prelude-fail-1.rs:16:9
|
LL | u8::clone!(); //~ ERROR failed to resolve. Not a module `u8`
| ^^ Not a module `u8`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0433`.

View File

@ -0,0 +1,19 @@
// 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(use_extern_macros)]
mod m {
fn check() {
Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
}
}
fn main() {}

View File

@ -0,0 +1,8 @@
error: fail to resolve non-ident macro path
--> $DIR/macro-path-prelude-fail-2.rs:15:9
|
LL | Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
| ^^^^^^^^^^
error: aborting due to previous error

View File

@ -0,0 +1,18 @@
// 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(use_extern_macros)]
#[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
struct S;
fn main() {
inline!(); //~ ERROR expected a macro, found non-macro attribute
}

View File

@ -0,0 +1,14 @@
error: expected a macro, found non-macro attribute
--> $DIR/macro-path-prelude-fail-3.rs:13:10
|
LL | #[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
| ^^^^^^
error: expected a macro, found non-macro attribute
--> $DIR/macro-path-prelude-fail-3.rs:17:5
|
LL | inline!(); //~ ERROR expected a macro, found non-macro attribute
| ^^^^^^
error: aborting due to 2 previous errors

View File

@ -8,8 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn main() {
#[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
let x =
3;
// compile-pass
#![feature(use_extern_macros, extern_prelude)]
mod m {
fn check() {
std::panic!(); // OK
}
}
fn main() {}

View File

@ -0,0 +1,41 @@
// 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:macro-in-other-crate.rs
#![feature(decl_macro, extern_prelude)]
macro_rules! add_macro_expanded_things_to_macro_prelude {() => {
#[macro_use]
extern crate macro_in_other_crate;
}}
add_macro_expanded_things_to_macro_prelude!();
mod m1 {
fn check() {
inline!(); //~ ERROR `inline` is ambiguous
}
}
mod m2 {
pub mod std {
pub macro panic() {}
}
}
mod m3 {
use m2::*; // glob-import user-defined `std`
fn check() {
std::panic!(); //~ ERROR `std` is ambiguous
}
}
fn main() {}

View File

@ -0,0 +1,42 @@
error[E0659]: `inline` is ambiguous
--> $DIR/macro-path-prelude-shadowing.rs:24:9
|
LL | inline!(); //~ ERROR `inline` is ambiguous
| ^^^^^^
|
note: `inline` could refer to the name imported here
--> $DIR/macro-path-prelude-shadowing.rs:16:5
|
LL | #[macro_use]
| ^^^^^^^^^^^^
...
LL | add_macro_expanded_things_to_macro_prelude!();
| ---------------------------------------------- in this macro invocation
note: `inline` could also refer to the name defined here
--> $DIR/macro-path-prelude-shadowing.rs:24:9
|
LL | inline!(); //~ ERROR `inline` is ambiguous
| ^^^^^^
= note: macro-expanded macro imports do not shadow
error[E0659]: `std` is ambiguous
--> $DIR/macro-path-prelude-shadowing.rs:37:9
|
LL | std::panic!(); //~ ERROR `std` is ambiguous
| ^^^^^^^^^^
|
note: `std` could refer to the name imported here
--> $DIR/macro-path-prelude-shadowing.rs:35:9
|
LL | use m2::*; // glob-import user-defined `std`
| ^^^^^
note: `std` could also refer to the name defined here
--> $DIR/macro-path-prelude-shadowing.rs:37:9
|
LL | std::panic!(); //~ ERROR `std` is ambiguous
| ^^^
= note: consider adding an explicit import of `std` to disambiguate
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0659`.

View File

@ -0,0 +1,15 @@
// 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.
// If macro modularization (`use_extern_macros`) is not enabled,
// then tool attributes are treated as custom attributes.
#[rustfmt::bar] //~ ERROR The attribute `rustfmt::bar` is currently unknown to the compiler
fn main() {}

View File

@ -0,0 +1,11 @@
error[E0658]: The attribute `rustfmt::bar` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
--> $DIR/tool-attributes-disabled-1.rs:14:1
|
LL | #[rustfmt::bar] //~ ERROR The attribute `rustfmt::bar` is currently unknown to the compiler
| ^^^^^^^^^^^^^^^
|
= help: add #![feature(custom_attribute)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,19 @@
// 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.
// If macro modularization (`use_extern_macros`) is not enabled,
// then tool attributes are treated as custom attributes.
// compile-pass
#![feature(custom_attribute)]
#[rustfmt::bar]
fn main() {}

View File

@ -0,0 +1,28 @@
// 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(tool_attributes)]
type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
#[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
struct S;
#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
fn check() {}
#[rustfmt::skip] // OK
fn main() {
rustfmt; //~ ERROR expected value, found tool module `rustfmt`
rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
}

View File

@ -0,0 +1,46 @@
error: cannot find derive macro `rustfmt` in this scope
--> $DIR/tool-attributes-misplaced-1.rs:16:10
|
LL | #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
| ^^^^^^^
error: cannot find attribute macro `rustfmt` in this scope
--> $DIR/tool-attributes-misplaced-1.rs:19:3
|
LL | #[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
| ^^^^^^^
error: cannot find macro `rustfmt!` in this scope
--> $DIR/tool-attributes-misplaced-1.rs:25:5
|
LL | rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
| ^^^^^^^
error[E0573]: expected type, found tool module `rustfmt`
--> $DIR/tool-attributes-misplaced-1.rs:13:10
|
LL | type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
| ^^^^^^^ not a type
error[E0573]: expected type, found non-macro attribute `rustfmt::skip`
--> $DIR/tool-attributes-misplaced-1.rs:14:10
|
LL | type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
| ^^^^^^^^^^^^^ not a type
error[E0423]: expected value, found tool module `rustfmt`
--> $DIR/tool-attributes-misplaced-1.rs:24:5
|
LL | rustfmt; //~ ERROR expected value, found tool module `rustfmt`
| ^^^^^^^ not a value
error[E0423]: expected value, found non-macro attribute `rustfmt::skip`
--> $DIR/tool-attributes-misplaced-1.rs:27:5
|
LL | rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
| ^^^^^^^^^^^^^ not a value
error: aborting due to 7 previous errors
Some errors occurred: E0423, E0573.
For more information about an error, try `rustc --explain E0423`.

View File

@ -0,0 +1,18 @@
// 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(tool_attributes)]
#[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
struct S;
fn main() {
rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
}

View File

@ -0,0 +1,14 @@
error: expected a macro, found non-macro attribute
--> $DIR/tool-attributes-misplaced-2.rs:13:10
|
LL | #[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
| ^^^^^^^^^^^^^
error: expected a macro, found non-macro attribute
--> $DIR/tool-attributes-misplaced-2.rs:17:5
|
LL | rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
| ^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -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(tool_attributes, proc_macro_path_invoc)]
mod rustfmt {}
#[rustfmt::skip] //~ ERROR failed to resolve. Could not find `skip` in `rustfmt`
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0433]: failed to resolve. Could not find `skip` in `rustfmt`
--> $DIR/tool-attributes-shadowing.rs:15:12
|
LL | #[rustfmt::skip] //~ ERROR failed to resolve. Could not find `skip` in `rustfmt`
| ^^^^ Could not find `skip` in `rustfmt`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0433`.