From c84562e019e3061c79879487ace098a652d19490 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 3 Aug 2018 02:30:03 +0300 Subject: Avoid modifying invocations in place for derive helper attributes --- src/libsyntax/ext/base.rs | 4 ++-- src/libsyntax/ext/expand.rs | 21 ++------------------- 2 files changed, 4 insertions(+), 21 deletions(-) (limited to 'src/libsyntax/ext') diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 8450daa3f7c..1bc5cb93c11 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -726,7 +726,7 @@ pub trait Resolver { fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec, allow_derive: bool) -> Option; - fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + fn resolve_invoc(&mut self, invoc: &Invocation, scope: Mark, force: bool) -> Result>, Determinacy>; fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) -> Result, Determinacy>; @@ -754,7 +754,7 @@ impl Resolver for DummyResolver { fn resolve_imports(&mut self) {} fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec, _allow_derive: bool) -> Option { None } - fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool) + fn resolve_invoc(&mut self, _invoc: &Invocation, _scope: Mark, _force: bool) -> Result>, Determinacy> { Err(Determinacy::Determined) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8bd30e43476..7148f3c00f2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -252,13 +252,6 @@ impl Invocation { InvocationKind::Derive { ref path, .. } => path.span, } } - - pub fn attr_id(&self) -> Option { - match self.kind { - InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id), - _ => None, - } - } } pub struct MacroExpander<'a, 'b:'a> { @@ -338,7 +331,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let mut undetermined_invocations = Vec::new(); let (mut progress, mut force) = (false, !self.monotonic); loop { - let mut invoc = if let Some(invoc) = invocations.pop() { + let invoc = if let Some(invoc) = invocations.pop() { invoc } else { self.resolve_imports(); @@ -350,20 +343,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; - let attr_id_before = invoc.attr_id(); - let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) { + let ext = match self.cx.resolver.resolve_invoc(&invoc, scope, force) { Ok(ext) => Some(ext), Err(Determinacy::Determined) => None, Err(Determinacy::Undetermined) => { - // Sometimes attributes which we thought were invocations - // end up being custom attributes for custom derives. If - // that's the case our `invoc` will have changed out from - // under us. If this is the case we're making progress so we - // want to flag it as such, and we test this by looking if - // the `attr_id()` method has been changing over time. - if invoc.attr_id() != attr_id_before { - progress = true; - } undetermined_invocations.push(invoc); continue } -- cgit 1.4.1-3-g733a5 From f60d96a4773db747aef75014ef6b41b39ae92372 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 4 Aug 2018 00:25:45 +0300 Subject: Support custom attributes when macro modularization is enabled --- src/librustc_resolve/build_reduced_graph.rs | 4 +- src/librustc_resolve/lib.rs | 7 +- src/librustc_resolve/macros.rs | 90 ++++++++++++++-------- src/libsyntax/ext/base.rs | 12 ++- src/libsyntax/ext/expand.rs | 22 +++--- src/libsyntax/feature_gate.rs | 47 ++--------- .../compile-fail/stmt_expr_attrs_no_feature.rs | 2 +- src/test/ui/tool-attributes-disabled-2.rs | 6 +- src/test/ui/tool-attributes-disabled-2.stderr | 11 +++ src/test/ui/tool-attributes-misplaced-1.rs | 4 +- src/test/ui/tool-attributes-misplaced-1.stderr | 8 +- 11 files changed, 108 insertions(+), 105 deletions(-) create mode 100644 src/test/ui/tool-attributes-disabled-2.stderr (limited to 'src/libsyntax/ext') diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f79e58f12a8..0be1bf3011e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -630,7 +630,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> { pub fn get_macro(&mut self, def: Def) -> Lrc { let def_id = match def { Def::Macro(def_id, ..) => def_id, - Def::NonMacroAttr(..) => return Lrc::new(SyntaxExtension::NonMacroAttr), + Def::NonMacroAttr(attr_kind) => return Lrc::new(SyntaxExtension::NonMacroAttr { + mark_used: attr_kind == NonMacroAttrKind::Tool, + }), _ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"), }; if let Some(ext) = self.macro_map.get(&def_id) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index cc5220de33b..d96967725f4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3485,8 +3485,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let binding = if let Some(module) = module { self.resolve_ident_in_module(module, ident, ns, record_used, path_span) } else if opt_ns == Some(MacroNS) { - self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span) - .map(MacroBinding::binding) + assert!(ns == TypeNS); + self.resolve_lexical_macro_path_segment(ident, ns, record_used, record_used, + false, path_span).map(MacroBinding::binding) } else { let record_used_id = if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None }; @@ -4549,6 +4550,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, false, + false, + true, attr.path.span); if let Ok(binding) = result { if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index a283992c804..b0fec11bf58 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -331,18 +331,29 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { } else if let Def::NonMacroAttr(attr_kind) = def { let is_attr_invoc = if let InvocationKind::Attr { .. } = invoc.kind { true } else { false }; + let path = invoc.path().expect("no path for non-macro attr"); match attr_kind { - NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper if is_attr_invoc => { + NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper | + NonMacroAttrKind::Custom if is_attr_invoc => { if attr_kind == NonMacroAttrKind::Tool && !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))); + if attr_kind == NonMacroAttrKind::Custom && + !self.session.features_untracked().custom_attribute { + let msg = format!("The attribute `{}` is currently unknown to the compiler \ + and may have meaning added to it in the future", path); + feature_err(&self.session.parse_sess, "custom_attribute", invoc.span(), + GateIssue::Language, &msg).emit(); + } + return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr { + mark_used: attr_kind == NonMacroAttrKind::Tool, + }))); } _ => { - self.report_non_macro_attr(invoc.path_span(), def); + self.report_non_macro_attr(path.span, def); return Err(Determinacy::Determined); } } @@ -418,43 +429,42 @@ impl<'a, 'cl> Resolver<'a, 'cl> { }; let path = attr.as_ref().unwrap().path.clone(); - let mut determinacy = Determinacy::Determined; - match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) { - Ok(def) => return Ok(def), - Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, - Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), - Err(Determinacy::Determined) => {} + let def = self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force); + if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = def {} else { + return def; } - // Ok at this point we've determined that the `attr` above doesn't - // actually resolve at this time, so we may want to report an error. - // It could be the case, though, that `attr` won't ever resolve! If - // there's a custom derive that could be used it might declare `attr` as - // a custom attribute accepted by the derive. In this case we don't want - // to report this particular invocation as unresolved, but rather we'd - // want to move on to the next invocation. + // At this point we've found that the `attr` is determinately unresolved and thus can be + // interpreted as a custom attribute. Normally custom attributes are feature gated, but + // it may be a custom attribute whitelisted by a derive macro and they do not require + // a feature gate. // - // This loop here looks through all of the derive annotations in scope - // and tries to resolve them. If they themselves successfully resolve - // *and* the resolve mentions that this attribute's name is a registered - // custom attribute then we return that custom attribute as the resolution result. - let attr_name = match path.segments.len() { - 1 => path.segments[0].ident.name, - _ => return Err(determinacy), - }; + // So here we look through all of the derive annotations in scope and try to resolve them. + // If they themselves successfully resolve *and* one of the resolved derive macros + // whitelists this attribute's name, then this is a registered attribute and we can convert + // it from a "generic custom attrite" into a "known derive helper attribute". + enum ConvertToDeriveHelper { Yes, No, DontKnow } + let mut convert_to_derive_helper = ConvertToDeriveHelper::No; + let attr_name = path.segments[0].ident.name; for path in traits { match self.resolve_macro(scope, path, MacroKind::Derive, force) { Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext { if inert_attrs.contains(&attr_name) { - return Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)); + convert_to_derive_helper = ConvertToDeriveHelper::Yes; + break } }, - Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, + Err(Determinacy::Undetermined) => + convert_to_derive_helper = ConvertToDeriveHelper::DontKnow, Err(Determinacy::Determined) => {} } } - Err(determinacy) + match convert_to_derive_helper { + ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)), + ConvertToDeriveHelper::No => def, + ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)), + } } fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) @@ -537,10 +547,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution { Ok(Def::Macro(binding.def_id, MacroKind::Bang)) } else { - match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, span) { + match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, force, + kind == MacroKind::Attr, span) { Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()), - Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), - Err(_) => { + Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), + Err(Determinacy::Determined) => { self.found_unresolved_macro = true; Err(Determinacy::Determined) } @@ -561,6 +572,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> { mut ident: Ident, ns: Namespace, record_used: bool, + force: bool, + is_attr: bool, path_span: Span) -> Result, Determinacy> { // General principles: @@ -591,6 +604,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // 3. Builtin attributes (closed, controlled). assert!(ns == TypeNS || ns == MacroNS); + let force = force || record_used; ident = ident.modern(); // Names from inner scope that can't shadow names from outer scopes, e.g. @@ -764,7 +778,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { Err(Determinacy::Determined) => { continue_search!(); } - Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), + Err(Determinacy::Undetermined) => return Err(Determinacy::determined(force)), } } @@ -773,7 +787,16 @@ impl<'a, 'cl> Resolver<'a, 'cl> { return Ok(previous_result); } - if record_used { Err(Determinacy::Determined) } else { Err(Determinacy::Undetermined) } + let determinacy = Determinacy::determined(force); + if determinacy == Determinacy::Determined && is_attr { + // For attributes interpret determinate "no solution" as a custom attribute. + let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom), + ty::Visibility::Public, ident.span, Mark::root()) + .to_name_binding(self.arenas); + Ok(MacroBinding::Global(binding)) + } else { + Err(determinacy) + } } pub fn resolve_legacy_scope(&mut self, @@ -857,7 +880,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let span = ident.span; let legacy_scope = &self.invocations[&mark].legacy_scope; let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident, true); - let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, span); + let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, true, + kind == MacroKind::Attr, span); let check_consistency = |this: &Self, binding: MacroBinding| { if let Some(def) = def { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1bc5cb93c11..de391ee4219 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -589,7 +589,7 @@ 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, + NonMacroAttr { mark_used: bool }, /// A syntax extension that is attached to an item and creates new items /// based upon it. @@ -670,7 +670,7 @@ impl SyntaxExtension { SyntaxExtension::IdentTT(..) | SyntaxExtension::ProcMacro { .. } => MacroKind::Bang, - SyntaxExtension::NonMacroAttr | + SyntaxExtension::NonMacroAttr { .. } | SyntaxExtension::MultiDecorator(..) | SyntaxExtension::MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => @@ -700,7 +700,7 @@ impl SyntaxExtension { SyntaxExtension::AttrProcMacro(.., edition) | SyntaxExtension::ProcMacroDerive(.., edition) => edition, // Unstable legacy stuff - SyntaxExtension::NonMacroAttr | + SyntaxExtension::NonMacroAttr { .. } | SyntaxExtension::IdentTT(..) | SyntaxExtension::MultiDecorator(..) | SyntaxExtension::MultiModifier(..) | @@ -739,6 +739,12 @@ pub enum Determinacy { Undetermined, } +impl Determinacy { + pub fn determined(determined: bool) -> Determinacy { + if determined { Determinacy::Determined } else { Determinacy::Undetermined } + } +} + pub struct DummyResolver; impl Resolver for DummyResolver { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 7148f3c00f2..72e0abfea8b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -244,12 +244,12 @@ impl Invocation { } } - pub fn path_span(&self) -> Span { + pub fn path(&self) -> Option<&Path> { 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, + InvocationKind::Bang { ref mac, .. } => Some(&mac.node.path), + InvocationKind::Attr { attr: Some(ref attr), .. } => Some(&attr.path), + InvocationKind::Attr { attr: None, .. } => None, + InvocationKind::Derive { ref path, .. } => Some(path), } } } @@ -548,7 +548,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; - attr::mark_used(&attr); + if let NonMacroAttr { mark_used: false } = *ext {} else { + attr::mark_used(&attr); + } invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: attr.span, def_site: None, @@ -560,7 +562,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); match *ext { - NonMacroAttr => { + 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))) @@ -810,7 +812,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } MultiDecorator(..) | MultiModifier(..) | - AttrProcMacro(..) | SyntaxExtension::NonMacroAttr => { + AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => { self.cx.span_err(path.span, &format!("`{}` can only be used in attributes", path)); self.cx.trace_macros_diag(); @@ -1487,7 +1489,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }; if attr.is_some() || !traits.is_empty() { - if !self.cx.ecfg.macros_in_extern_enabled() { + if !self.cx.ecfg.macros_in_extern_enabled() && + !self.cx.ecfg.custom_attribute_enabled() { if let Some(ref attr) = attr { emit_feature_err(&self.cx.parse_sess, "macros_in_extern", attr.span, GateIssue::Language, explain); @@ -1668,6 +1671,7 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_custom_derive = custom_derive, fn enable_format_args_nl = format_args_nl, fn macros_in_extern_enabled = macros_in_extern, + fn custom_attribute_enabled = custom_attribute, fn proc_macro_mod = proc_macro_mod, fn proc_macro_gen = proc_macro_gen, fn proc_macro_expr = proc_macro_expr, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 193e560893f..3f4ee834256 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -32,7 +32,7 @@ use attr; use codemap::Spanned; use edition::{ALL_EDITIONS, Edition}; use syntax_pos::{Span, DUMMY_SP}; -use errors::{DiagnosticBuilder, Handler, FatalError}; +use errors::{DiagnosticBuilder, Handler}; use visit::{self, FnKind, Visitor}; use parse::ParseSess; use symbol::{keywords, Symbol}; @@ -83,8 +83,10 @@ macro_rules! declare_features { } 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 + // The `decl_macro`, `tool_attributes` and `custom_attributes` + // features imply `use_extern_macros`. + self.use_extern_macros || self.decl_macro || + self.tool_attributes || self.custom_attribute } } }; @@ -1898,9 +1900,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } let mut features = Features::new(); - - let mut feature_checker = FeatureChecker::default(); - let mut edition_enabled_features = FxHashMap(); for &(name, .., f_edition, set) in ACTIVE_FEATURES.iter() { @@ -1989,45 +1988,9 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } } - feature_checker.check(span_handler); - features } -/// A collector for mutually exclusive and interdependent features and their flag spans. -#[derive(Default)] -struct FeatureChecker { - use_extern_macros: Option, - custom_attribute: Option, -} - -impl FeatureChecker { - // If this method turns out to be a hotspot due to branching, - // 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 self.use_extern_macros is None, set to Some(span) - self.use_extern_macros = self.use_extern_macros.or(Some(span)); - } - - if features.custom_attribute { - self.custom_attribute = self.custom_attribute.or(Some(span)); - } - } - - fn check(self, handler: &Handler) { - if let (Some(pm_span), Some(ca_span)) = (self.use_extern_macros, self.custom_attribute) { - handler.struct_span_err(pm_span, "Cannot use `#![feature(use_extern_macros)]` and \ - `#![feature(custom_attribute)] at the same time") - .span_note(ca_span, "`#![feature(custom_attribute)]` declared here") - .emit(); - - FatalError.raise(); - } - } -} - pub fn check_crate(krate: &ast::Crate, sess: &ParseSess, features: &Features, diff --git a/src/test/compile-fail/stmt_expr_attrs_no_feature.rs b/src/test/compile-fail/stmt_expr_attrs_no_feature.rs index d8626dfd39e..896817bb858 100644 --- a/src/test/compile-fail/stmt_expr_attrs_no_feature.rs +++ b/src/test/compile-fail/stmt_expr_attrs_no_feature.rs @@ -20,7 +20,7 @@ fn main() { #[attr] fn a() {} - #[attr] + #[attr] //~ ERROR attributes on expressions are experimental { } diff --git a/src/test/ui/tool-attributes-disabled-2.rs b/src/test/ui/tool-attributes-disabled-2.rs index 160dda05b1e..2d97e160f49 100644 --- a/src/test/ui/tool-attributes-disabled-2.rs +++ b/src/test/ui/tool-attributes-disabled-2.rs @@ -11,9 +11,5 @@ // If macro modularization (`use_extern_macros`) is not enabled, // then tool attributes are treated as custom attributes. -// compile-pass - -#![feature(custom_attribute)] - -#[rustfmt::bar] +#[rustfmt::bar] //~ ERROR attribute `rustfmt::bar` is currently unknown to the compiler fn main() {} diff --git a/src/test/ui/tool-attributes-disabled-2.stderr b/src/test/ui/tool-attributes-disabled-2.stderr new file mode 100644 index 00000000000..b327773dd6a --- /dev/null +++ b/src/test/ui/tool-attributes-disabled-2.stderr @@ -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-2.rs:14:1 + | +LL | #[rustfmt::bar] //~ ERROR 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`. diff --git a/src/test/ui/tool-attributes-misplaced-1.rs b/src/test/ui/tool-attributes-misplaced-1.rs index bdbd80e7a01..7a6b9ae9943 100644 --- a/src/test/ui/tool-attributes-misplaced-1.rs +++ b/src/test/ui/tool-attributes-misplaced-1.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_attributes)] +#![feature(tool_attributes, custom_attribute)] type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt` type B = rustfmt::skip; //~ ERROR expected type, found tool attribute `rustfmt::skip` @@ -16,7 +16,7 @@ type B = rustfmt::skip; //~ ERROR expected type, found tool attribute `rustfmt:: #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope struct S; -#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope +#[rustfmt] // OK, interpreted as a custom attribute fn check() {} #[rustfmt::skip] // OK diff --git a/src/test/ui/tool-attributes-misplaced-1.stderr b/src/test/ui/tool-attributes-misplaced-1.stderr index 5673c7f5305..60188aebce7 100644 --- a/src/test/ui/tool-attributes-misplaced-1.stderr +++ b/src/test/ui/tool-attributes-misplaced-1.stderr @@ -4,12 +4,6 @@ error: cannot find derive macro `rustfmt` in this scope 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 | @@ -40,7 +34,7 @@ error[E0423]: expected value, found tool attribute `rustfmt::skip` LL | rustfmt::skip; //~ ERROR expected value, found tool attribute `rustfmt::skip` | ^^^^^^^^^^^^^ not a value -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors Some errors occurred: E0423, E0573. For more information about an error, try `rustc --explain E0423`. -- cgit 1.4.1-3-g733a5 From 50886115d7a7eba43b025e608aa156ef0e8dd7a8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 4 Aug 2018 05:17:51 +0300 Subject: Address review comments Adjust a few fulldeps and pretty-printing tests Fix rebase --- src/librustc_resolve/macros.rs | 10 +++++-- src/libsyntax/ext/expand.rs | 34 ++++++++-------------- src/libsyntax/feature_gate.rs | 8 ----- .../proc-macro/issue-41211.rs | 2 +- .../proc-macro/macros-in-extern.rs | 6 ++-- .../proc-macro/proc-macro-custom-attr-mutex.rs | 25 ---------------- src/test/compile-fail/macros-in-extern.rs | 6 ++-- src/test/pretty/attr-literals.rs | 2 +- src/test/ui-fulldeps/resolve-error.rs | 8 ++--- src/test/ui-fulldeps/resolve-error.stderr | 28 +++++------------- src/test/ui/custom-attribute-multisegment.rs | 18 ++++++++++++ src/test/ui/custom-attribute-multisegment.stderr | 9 ++++++ src/test/ui/feature-gate-macros_in_extern.rs | 6 ++-- src/test/ui/feature-gate-macros_in_extern.stderr | 6 ++-- 14 files changed, 72 insertions(+), 96 deletions(-) delete mode 100644 src/test/compile-fail-fulldeps/proc-macro/proc-macro-custom-attr-mutex.rs create mode 100644 src/test/ui/custom-attribute-multisegment.rs create mode 100644 src/test/ui/custom-attribute-multisegment.stderr (limited to 'src/libsyntax/ext') diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index b0fec11bf58..d680b2d9f7d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -329,6 +329,9 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { self.report_proc_macro_stub(invoc.span()); return Err(Determinacy::Determined); } else if let Def::NonMacroAttr(attr_kind) = def { + // Note that not only attributes, but anything in macro namespace can result in a + // `Def::NonMacroAttr` definition (e.g. `inline!()`), so we must report the error + // below for these cases. let is_attr_invoc = if let InvocationKind::Attr { .. } = invoc.kind { true } else { false }; let path = invoc.path().expect("no path for non-macro attr"); @@ -604,7 +607,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // 3. Builtin attributes (closed, controlled). assert!(ns == TypeNS || ns == MacroNS); - let force = force || record_used; + assert!(force || !record_used); // `record_used` implies `force` ident = ident.modern(); // Names from inner scope that can't shadow names from outer scopes, e.g. @@ -789,7 +792,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let determinacy = Determinacy::determined(force); if determinacy == Determinacy::Determined && is_attr { - // For attributes interpret determinate "no solution" as a custom attribute. + // For single-segment attributes interpret determinate "no resolution" as a custom + // attribute. (Lexical resolution implies the first segment and is_attr should imply + // the last segment, so we are certainly working with a single-segment attribute here.) + assert!(ns == MacroNS); let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom), ty::Visibility::Public, ident.span, Mark::root()) .to_name_binding(self.arenas); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 72e0abfea8b..12941a85669 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -516,6 +516,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option { + if invoc.fragment_kind == AstFragmentKind::ForeignItems && + !self.cx.ecfg.macros_in_extern_enabled() { + if let SyntaxExtension::NonMacroAttr { .. } = *ext {} else { + emit_feature_err(&self.cx.parse_sess, "macros_in_extern", + invoc.span(), GateIssue::Language, + "macro invocations in `extern {}` blocks are experimental"); + } + } + let result = match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext)?, InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext)?, @@ -549,6 +558,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; if let NonMacroAttr { mark_used: false } = *ext {} else { + // Macro attrs are always used when expanded, + // non-macro attrs are considered used when the field says so. attr::mark_used(&attr); } invoc.expansion_data.mark.set_expn_info(ExpnInfo { @@ -1482,21 +1493,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { foreign_item: ast::ForeignItem) -> SmallVector { let (attr, traits, foreign_item) = self.classify_item(foreign_item); - let explain = if self.cx.ecfg.use_extern_macros_enabled() { - feature_gate::EXPLAIN_PROC_MACROS_IN_EXTERN - } else { - feature_gate::EXPLAIN_MACROS_IN_EXTERN - }; - - if attr.is_some() || !traits.is_empty() { - if !self.cx.ecfg.macros_in_extern_enabled() && - !self.cx.ecfg.custom_attribute_enabled() { - if let Some(ref attr) = attr { - emit_feature_err(&self.cx.parse_sess, "macros_in_extern", attr.span, - GateIssue::Language, explain); - } - } - + if attr.is_some() || !traits.is_empty() { let item = Annotatable::ForeignItem(P(foreign_item)); return self.collect_attr(attr, traits, item, AstFragmentKind::ForeignItems) .make_foreign_items(); @@ -1504,12 +1501,6 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { if let ast::ForeignItemKind::Macro(mac) = foreign_item.node { self.check_attributes(&foreign_item.attrs); - - if !self.cx.ecfg.macros_in_extern_enabled() { - emit_feature_err(&self.cx.parse_sess, "macros_in_extern", foreign_item.span, - GateIssue::Language, explain); - } - return self.collect_bang(mac, foreign_item.span, AstFragmentKind::ForeignItems) .make_foreign_items(); } @@ -1671,7 +1662,6 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_custom_derive = custom_derive, fn enable_format_args_nl = format_args_nl, fn macros_in_extern_enabled = macros_in_extern, - fn custom_attribute_enabled = custom_attribute, fn proc_macro_mod = proc_macro_mod, fn proc_macro_gen = proc_macro_gen, fn proc_macro_expr = proc_macro_expr, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a7a29edf0a0..119505896d6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1354,13 +1354,6 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str = "using the `?` macro Kleene operator for \"at most one\" repetition is unstable"; -pub const EXPLAIN_MACROS_IN_EXTERN: &'static str = - "macro invocations in `extern {}` blocks are experimental."; - -// mention proc-macros when enabled -pub const EXPLAIN_PROC_MACROS_IN_EXTERN: &'static str = - "macro and proc-macro invocations in `extern {}` blocks are experimental."; - struct PostExpansionVisitor<'a> { context: &'a Context<'a>, } @@ -1969,7 +1962,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], ).emit(); } else { set(&mut features, mi.span); - feature_checker.collect(&features, mi.span); features.declared_lang_features.push((name, mi.span, None)); } continue diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs index 8fced7d8c70..f71d4b86f1e 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs @@ -15,7 +15,7 @@ #![feature(use_extern_macros)] #![emit_unchanged] -//~^ ERROR: cannot find attribute macro `emit_unchanged` in this scope +//~^ ERROR attribute `emit_unchanged` is currently unknown to the compiler extern crate issue_41211; use issue_41211::emit_unchanged; diff --git a/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs index 9a35dc0edc4..e418ecc114c 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs @@ -26,13 +26,13 @@ fn main() { #[link(name = "rust_test_helpers", kind = "static")] extern { #[no_output] - //~^ ERROR macro and proc-macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental fn some_definitely_unknown_symbol_which_should_be_removed(); #[nop_attr] - //~^ ERROR macro and proc-macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental fn rust_get_test_int() -> isize; emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); - //~^ ERROR macro and proc-macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental } diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-custom-attr-mutex.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-custom-attr-mutex.rs deleted file mode 100644 index 8640aa2387f..00000000000 --- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-custom-attr-mutex.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:attr_proc_macro.rs -// ignore-tidy-linelength - -#![feature(custom_attribute)] -//~^ ERROR Cannot use `#![feature(use_extern_macros)]` and `#![feature(custom_attribute)] at the same time - -extern crate attr_proc_macro; -use attr_proc_macro::attr_proc_macro; - -#[attr_proc_macro] -fn foo() {} - -fn main() { - foo(); -} diff --git a/src/test/compile-fail/macros-in-extern.rs b/src/test/compile-fail/macros-in-extern.rs index b6e273881cc..40053853b15 100644 --- a/src/test/compile-fail/macros-in-extern.rs +++ b/src/test/compile-fail/macros-in-extern.rs @@ -34,9 +34,9 @@ fn main() { #[link(name = "rust_test_helpers", kind = "static")] extern { returns_isize!(rust_get_test_int); - //~^ ERROR macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - //~^ ERROR macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental emits_nothing!(); - //~^ ERROR macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental } diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs index ba8c580cb0a..ce157e3632c 100644 --- a/src/test/pretty/attr-literals.rs +++ b/src/test/pretty/attr-literals.rs @@ -18,6 +18,6 @@ fn main() { #[align = 8] fn f() { } - #[vec(1, 2, 3)] + #[vector(1, 2, 3)] fn g() { } } diff --git a/src/test/ui-fulldeps/resolve-error.rs b/src/test/ui-fulldeps/resolve-error.rs index df9b263534f..1940151357c 100644 --- a/src/test/ui-fulldeps/resolve-error.rs +++ b/src/test/ui-fulldeps/resolve-error.rs @@ -13,7 +13,7 @@ // aux-build:attr_proc_macro.rs // aux-build:bang_proc_macro.rs -#![feature(use_extern_macros)] +#![feature(custom_attribute)] #[macro_use] extern crate derive_foo; @@ -37,12 +37,10 @@ macro_rules! attr_proc_mac { //~^ ERROR cannot find struct Foo; -#[attr_proc_macra] -//~^ ERROR cannot find +#[attr_proc_macra] // OK, interpreted as a custom attribute struct Bar; -#[FooWithLongNan] -//~^ ERROR cannot find +#[FooWithLongNan] // OK, interpreted as a custom attribute struct Asdf; #[derive(Dlone)] diff --git a/src/test/ui-fulldeps/resolve-error.stderr b/src/test/ui-fulldeps/resolve-error.stderr index caa79664614..278409c688a 100644 --- a/src/test/ui-fulldeps/resolve-error.stderr +++ b/src/test/ui-fulldeps/resolve-error.stderr @@ -4,59 +4,47 @@ error: cannot find derive macro `FooWithLongNan` in this scope LL | #[derive(FooWithLongNan)] | ^^^^^^^^^^^^^^ help: try: `FooWithLongName` -error: cannot find attribute macro `attr_proc_macra` in this scope - --> $DIR/resolve-error.rs:40:3 - | -LL | #[attr_proc_macra] - | ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro` - -error: cannot find attribute macro `FooWithLongNan` in this scope - --> $DIR/resolve-error.rs:44:3 - | -LL | #[FooWithLongNan] - | ^^^^^^^^^^^^^^ - error: cannot find derive macro `Dlone` in this scope - --> $DIR/resolve-error.rs:48:10 + --> $DIR/resolve-error.rs:46:10 | LL | #[derive(Dlone)] | ^^^^^ help: try: `Clone` error: cannot find derive macro `Dlona` in this scope - --> $DIR/resolve-error.rs:52:10 + --> $DIR/resolve-error.rs:50:10 | LL | #[derive(Dlona)] | ^^^^^ help: try: `Clona` error: cannot find derive macro `attr_proc_macra` in this scope - --> $DIR/resolve-error.rs:56:10 + --> $DIR/resolve-error.rs:54:10 | LL | #[derive(attr_proc_macra)] | ^^^^^^^^^^^^^^^ error: cannot find macro `FooWithLongNama!` in this scope - --> $DIR/resolve-error.rs:61:5 + --> $DIR/resolve-error.rs:59:5 | LL | FooWithLongNama!(); | ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam` error: cannot find macro `attr_proc_macra!` in this scope - --> $DIR/resolve-error.rs:64:5 + --> $DIR/resolve-error.rs:62:5 | LL | attr_proc_macra!(); | ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac` error: cannot find macro `Dlona!` in this scope - --> $DIR/resolve-error.rs:67:5 + --> $DIR/resolve-error.rs:65:5 | LL | Dlona!(); | ^^^^^ error: cannot find macro `bang_proc_macrp!` in this scope - --> $DIR/resolve-error.rs:70:5 + --> $DIR/resolve-error.rs:68:5 | LL | bang_proc_macrp!(); | ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro` -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors diff --git a/src/test/ui/custom-attribute-multisegment.rs b/src/test/ui/custom-attribute-multisegment.rs new file mode 100644 index 00000000000..ad8e0e76e14 --- /dev/null +++ b/src/test/ui/custom-attribute-multisegment.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Unresolved multi-segment attributes are not treated as custom. + +#![feature(custom_attribute, proc_macro_path_invoc)] + +mod existent {} + +#[existent::nonexistent] //~ ERROR failed to resolve. Could not find `nonexistent` in `existent` +fn main() {} diff --git a/src/test/ui/custom-attribute-multisegment.stderr b/src/test/ui/custom-attribute-multisegment.stderr new file mode 100644 index 00000000000..ff72d1c36d8 --- /dev/null +++ b/src/test/ui/custom-attribute-multisegment.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve. Could not find `nonexistent` in `existent` + --> $DIR/custom-attribute-multisegment.rs:17:13 + | +LL | #[existent::nonexistent] //~ ERROR failed to resolve. Could not find `nonexistent` in `existent` + | ^^^^^^^^^^^ Could not find `nonexistent` in `existent` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gate-macros_in_extern.rs index 5271f75b632..77080e3c348 100644 --- a/src/test/ui/feature-gate-macros_in_extern.rs +++ b/src/test/ui/feature-gate-macros_in_extern.rs @@ -27,9 +27,9 @@ macro_rules! emits_nothing( #[link(name = "rust_test_helpers", kind = "static")] extern { returns_isize!(rust_get_test_int); - //~^ ERROR macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - //~^ ERROR macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental emits_nothing!(); - //~^ ERROR macro invocations in `extern {}` blocks are experimental. + //~^ ERROR macro invocations in `extern {}` blocks are experimental } diff --git a/src/test/ui/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gate-macros_in_extern.stderr index 5d7e01fbbb7..23b63078dbf 100644 --- a/src/test/ui/feature-gate-macros_in_extern.stderr +++ b/src/test/ui/feature-gate-macros_in_extern.stderr @@ -1,4 +1,4 @@ -error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476) +error[E0658]: 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 and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476) +error[E0658]: 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 and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) --> $DIR/feature-gate-macros_in_extern.rs:33:5 | LL | emits_nothing!(); -- cgit 1.4.1-3-g733a5