From a4a07e00ced90e076dbadd8b350db527bcc588bd Mon Sep 17 00:00:00 2001 From: Tobia Date: Mon, 1 Apr 2019 18:16:03 +0900 Subject: [PATCH 01/20] Replaced linear token counting macros with optimized implementation --- src/librustc/hir/map/definitions.rs | 12 ++++++++++-- src/libserialize/serialize.rs | 17 ++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 1006d813e65ed..c72edb6cc6d72 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -696,9 +696,17 @@ impl DefPathData { } } +/// Evaluates to the number of tokens passed to it. +/// +/// Logarithmic counting: every one or two recursive expansions, the number of +/// tokens to count is divided by two, instead of being reduced by one. +/// Therefore, the recursion depth is the binary logarithm of the number of +/// tokens to count, and the expanded tree is likewise very small. macro_rules! count { - () => (0usize); - ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*)); + () => (0usize); + ($one:tt) => (1usize); + ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize); + ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize); } // We define the GlobalMetaDataKind enum with this macro because we want to diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index cf948078b08c5..d53891828f1c0 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -723,10 +723,17 @@ macro_rules! peel { ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* }) } -/// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3 -macro_rules! count_idents { - () => { 0 }; - ($_i:ident, $($rest:ident,)*) => { 1 + count_idents!($($rest,)*) } +/// Evaluates to the number of tokens passed to it. +/// +/// Logarithmic counting: every one or two recursive expansions, the number of +/// tokens to count is divided by two, instead of being reduced by one. +/// Therefore, the recursion depth is the binary logarithm of the number of +/// tokens to count, and the expanded tree is likewise very small. +macro_rules! count { + () => (0usize); + ($one:tt) => (1usize); + ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize); + ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize); } macro_rules! tuple { @@ -735,7 +742,7 @@ macro_rules! tuple { impl<$($name:Decodable),*> Decodable for ($($name,)*) { #[allow(non_snake_case)] fn decode(d: &mut D) -> Result<($($name,)*), D::Error> { - let len: usize = count_idents!($($name,)*); + let len: usize = count!($($name)*); d.read_tuple(len, |d| { let mut i = 0; let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> { From 97a5173df4e8ecb274117476e613f4af1e0f6324 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 6 Jun 2019 21:10:16 +0300 Subject: [PATCH 02/20] syntax: Remove `SyntaxExtension::IdentTT` and `IdentMacroExpander` --- src/librustc_plugin/registry.rs | 5 +---- src/libsyntax/ext/base.rs | 38 --------------------------------- src/libsyntax/ext/expand.rs | 22 ------------------- 3 files changed, 1 insertion(+), 64 deletions(-) diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 2ed6f868fa1ee..967fdcd2e7d41 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -4,7 +4,7 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; -use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT}; +use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; use syntax::ext::base::MacroExpanderFn; use syntax::symbol::{Symbol, sym}; use syntax::ast; @@ -109,9 +109,6 @@ impl<'a> Registry<'a> { edition, } } - IdentTT { expander, span: _, allow_internal_unstable } => { - IdentTT { expander, span: Some(self.krate_span), allow_internal_unstable } - } _ => extension, })); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 4b5b9ff7bbeee..e9a1e26038c47 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -285,34 +285,6 @@ impl TTMacroExpander for F } } -pub trait IdentMacroExpander { - fn expand<'cx>(&self, - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - ident: ast::Ident, - token_tree: Vec) - -> Box; -} - -pub type IdentMacroExpanderFn = - for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, ast::Ident, Vec) - -> Box; - -impl IdentMacroExpander for F - where F : for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, ast::Ident, - Vec) -> Box -{ - fn expand<'cx>(&self, - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - ident: ast::Ident, - token_tree: Vec) - -> Box - { - (*self)(cx, sp, ident, token_tree) - } -} - // Use a macro because forwarding to a simple function has type system issues macro_rules! make_stmts_default { ($me:expr) => { @@ -655,14 +627,6 @@ pub enum SyntaxExtension { edition: Edition, }, - /// A function-like syntax extension that has an extra ident before - /// the block. - IdentTT { - expander: Box, - span: Option, - allow_internal_unstable: Option>, - }, - /// An attribute-like procedural macro. TokenStream -> TokenStream. /// The input is the annotated item. /// Allows generating code to implement a Trait for a given struct @@ -688,7 +652,6 @@ impl SyntaxExtension { match *self { SyntaxExtension::DeclMacro { .. } | SyntaxExtension::NormalTT { .. } | - SyntaxExtension::IdentTT { .. } | SyntaxExtension::ProcMacro { .. } => MacroKind::Bang, SyntaxExtension::NonMacroAttr { .. } | @@ -722,7 +685,6 @@ impl SyntaxExtension { SyntaxExtension::ProcMacroDerive(.., edition) => edition, // Unstable legacy stuff SyntaxExtension::NonMacroAttr { .. } | - SyntaxExtension::IdentTT { .. } | SyntaxExtension::MultiDecorator(..) | SyntaxExtension::MultiModifier(..) | SyntaxExtension::BuiltinDerive(..) => default_edition, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c2a73b662c680..bb69a758dcdc8 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -791,28 +791,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - IdentTT { ref expander, span: tt_span, ref allow_internal_unstable } => { - if ident.name == kw::Invalid { - self.cx.span_err(path.span, - &format!("macro {}! expects an ident argument", path)); - self.cx.trace_macros_diag(); - kind.dummy(span) - } else { - invoc.expansion_data.mark.set_expn_info(ExpnInfo { - call_site: span, - def_site: tt_span, - format: macro_bang_format(path), - allow_internal_unstable: allow_internal_unstable.clone(), - allow_internal_unsafe: false, - local_inner_macros: false, - edition: self.cx.parse_sess.edition, - }); - - let input: Vec<_> = mac.node.stream().into_trees().collect(); - kind.make_from(expander.expand(self.cx, span, ident, input)) - } - } - MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => { self.cx.span_err(path.span, From 4419af8ae9939e208cc47387e3bdfb286f922f12 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 6 Jun 2019 21:38:27 +0300 Subject: [PATCH 03/20] Remove `SyntaxExtension::MultiDecorator` and `MultiItemDecorator` --- src/libsyntax/ext/base.rs | 33 -------- src/libsyntax/ext/expand.rs | 11 +-- .../auxiliary/custom-derive-partial-eq.rs | 71 ---------------- .../auxiliary/custom-derive-plugin-attr.rs | 84 ------------------- .../auxiliary/custom-derive-plugin.rs | 76 ----------------- .../custom-derive-partial-eq.rs | 10 --- .../run-pass-fulldeps/derive-totalsum-attr.rs | 64 -------------- src/test/run-pass-fulldeps/derive-totalsum.rs | 49 ----------- src/test/run-pass-fulldeps/issue-40663.rs | 13 --- 9 files changed, 1 insertion(+), 410 deletions(-) delete mode 100644 src/test/run-pass-fulldeps/auxiliary/custom-derive-partial-eq.rs delete mode 100644 src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs delete mode 100644 src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin.rs delete mode 100644 src/test/run-pass-fulldeps/custom-derive-partial-eq.rs delete mode 100644 src/test/run-pass-fulldeps/derive-totalsum-attr.rs delete mode 100644 src/test/run-pass-fulldeps/derive-totalsum.rs delete mode 100644 src/test/run-pass-fulldeps/issue-40663.rs diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e9a1e26038c47..1a716c3faef1d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -137,29 +137,6 @@ impl Annotatable { } } -// A more flexible ItemDecorator. -pub trait MultiItemDecorator { - fn expand(&self, - ecx: &mut ExtCtxt<'_>, - sp: Span, - meta_item: &ast::MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)); -} - -impl MultiItemDecorator for F - where F : Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)) -{ - fn expand(&self, - ecx: &mut ExtCtxt<'_>, - sp: Span, - meta_item: &ast::MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { - (*self)(ecx, sp, meta_item, item, push) - } -} - // `meta_item` is the annotation, and `item` is the item being modified. // FIXME Decorators should follow the same pattern too. pub trait MultiItemModifier { @@ -578,14 +555,6 @@ pub enum SyntaxExtension { /// A trivial "extension" that does nothing, only keeps the attribute and marks it as known. NonMacroAttr { mark_used: bool }, - /// A syntax extension that is attached to an item and creates new items - /// based upon it. - /// - /// `#[derive(...)]` is a `MultiItemDecorator`. - /// - /// Prefer ProcMacro or MultiModifier since they are more flexible. - MultiDecorator(Box), - /// A syntax extension that is attached to an item and modifies it /// in-place. Also allows decoration, i.e., creating new items. MultiModifier(Box), @@ -655,7 +624,6 @@ impl SyntaxExtension { SyntaxExtension::ProcMacro { .. } => MacroKind::Bang, SyntaxExtension::NonMacroAttr { .. } | - SyntaxExtension::MultiDecorator(..) | SyntaxExtension::MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => MacroKind::Attr, @@ -685,7 +653,6 @@ impl SyntaxExtension { SyntaxExtension::ProcMacroDerive(.., edition) => edition, // Unstable legacy stuff SyntaxExtension::NonMacroAttr { .. } | - SyntaxExtension::MultiDecorator(..) | SyntaxExtension::MultiModifier(..) | SyntaxExtension::BuiltinDerive(..) => default_edition, } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index bb69a758dcdc8..7d2928ef1807b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -575,14 +575,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item = mac.expand(self.cx, attr.span, &meta, item); Some(invoc.fragment_kind.expect_from_annotatables(item)) } - MultiDecorator(ref mac) => { - let mut items = Vec::new(); - let meta = attr.parse_meta(self.cx.parse_sess) - .expect("derive meta should already have been parsed"); - mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item)); - items.push(item); - Some(invoc.fragment_kind.expect_from_annotatables(items)) - } AttrProcMacro(ref mac, ..) => { self.gate_proc_macro_attr_item(attr.span, &item); let item_tok = TokenTree::Token(DUMMY_SP, Token::Interpolated(Lrc::new(match item { @@ -791,8 +783,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - MultiDecorator(..) | MultiModifier(..) | - AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => { + MultiModifier(..) | AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => { self.cx.span_err(path.span, &format!("`{}` can only be used in attributes", path)); self.cx.trace_macros_diag(); diff --git a/src/test/run-pass-fulldeps/auxiliary/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/auxiliary/custom-derive-partial-eq.rs deleted file mode 100644 index 4d6ff47a3ee91..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/custom-derive-partial-eq.rs +++ /dev/null @@ -1,71 +0,0 @@ -// force-host - -#![feature(plugin_registrar, rustc_private)] - -extern crate syntax; -extern crate syntax_ext; -extern crate rustc_plugin; - -use syntax_ext::deriving; -use deriving::generic::*; -use deriving::generic::ty::*; - -use rustc_plugin::Registry; -use syntax::ast::*; -use syntax::source_map::Span; -use syntax::ext::base::*; -use syntax::ext::build::AstBuilder; -use syntax::symbol::Symbol; -use syntax::ptr::P; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(Symbol::intern("derive_CustomPartialEq"), - MultiDecorator(Box::new(expand_deriving_partial_eq))); -} - -fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) { - // structures are equal if all fields are equal, and non equal, if - // any fields are not equal or if the enum variants are different - fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold(true, - |cx, span, subexpr, self_f, other_fs| { - let other_f = (other_fs.len(), other_fs.get(0)).1.unwrap(); - let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); - cx.expr_binary(span, BinOpKind::And, subexpr, eq) - }, - cx.expr_bool(span, true), - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, - span, - substr) - } - - let inline = cx.meta_word(span, Symbol::intern("inline")); - let attrs = vec![cx.attribute(span, inline)]; - let methods = vec![MethodDef { - name: "eq", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), "other")], - ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(cs_eq)), - }]; - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: deriving::generic::ty::Path::new(vec!["cmp", "PartialEq"]), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - is_unsafe: false, - supports_unions: false, - methods: methods, - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} diff --git a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs deleted file mode 100644 index c6b33fbc75ee2..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs +++ /dev/null @@ -1,84 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(box_syntax)] -#![feature(rustc_private)] - -extern crate syntax; -extern crate syntax_ext; -extern crate syntax_pos; -extern crate rustc; -extern crate rustc_plugin; - -use syntax::ast; -use syntax::attr; -use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; -use syntax::ext::build::AstBuilder; -use syntax::symbol::{Symbol, sym}; -use syntax::ptr::P; -use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure}; -use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching}; -use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; -use syntax_pos::Span; -use rustc_plugin::Registry; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension( - Symbol::intern("rustc_derive_TotalSum"), - MultiDecorator(box expand)); -} - -fn expand(cx: &mut ExtCtxt, - span: Span, - mitem: &ast::MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) { - let trait_def = TraitDef { - span: span, - attributes: vec![], - path: Path::new_local("TotalSum"), - additional_bounds: vec![], - generics: LifetimeBounds::empty(), - associated_types: vec![], - is_unsafe: false, - supports_unions: false, - methods: vec![ - MethodDef { - name: "total_sum", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![], - ret_ty: Literal(Path::new_local("isize")), - attributes: vec![], - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(totalsum_substructure)), - }, - ], - }; - - trait_def.expand(cx, mitem, item, push) -} - -// Mostly copied from syntax::ext::deriving::hash -/// Defines how the implementation for `trace()` is to be generated -fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure) -> P { - let fields = match *substr.fields { - Struct(_, ref fs) | EnumMatching(.., ref fs) => fs, - _ => cx.span_bug(trait_span, "impossible substructure") - }; - - fields.iter().fold(cx.expr_isize(trait_span, 0), |acc, ref item| { - if attr::contains_name(&item.attrs, sym::ignore) { - acc - } else { - cx.expr_binary(item.span, ast::BinOpKind::Add, acc, - cx.expr_method_call(item.span, - item.self_.clone(), - substr.method_ident, - Vec::new())) - } - }) -} diff --git a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin.rs deleted file mode 100644 index 874a0ec7c13fb..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin.rs +++ /dev/null @@ -1,76 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(box_syntax)] -#![feature(rustc_private)] - -extern crate syntax; -extern crate syntax_ext; -extern crate syntax_pos; -extern crate rustc; -extern crate rustc_plugin; - -use syntax::ast; -use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; -use syntax::ext::build::AstBuilder; -use syntax::symbol::Symbol; -use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure}; -use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; -use syntax_pos::Span; -use rustc_plugin::Registry; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension( - Symbol::intern("derive_TotalSum"), - MultiDecorator(box expand)); - - reg.register_syntax_extension( - Symbol::intern("derive_Nothing"), - MultiDecorator(box noop)); -} - -fn noop(_: &mut ExtCtxt, _: Span, _: &ast::MetaItem, _: &Annotatable, _: &mut FnMut(Annotatable)) {} - -fn expand(cx: &mut ExtCtxt, - span: Span, - mitem: &ast::MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) { - let trait_def = TraitDef { - span: span, - attributes: vec![], - path: Path::new_local("TotalSum"), - additional_bounds: vec![], - generics: LifetimeBounds::empty(), - associated_types: vec![], - is_unsafe: false, - supports_unions: false, - methods: vec![ - MethodDef { - name: "total_sum", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![], - ret_ty: Literal(Path::new_local("isize")), - attributes: vec![], - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(box |cx, span, substr| { - let zero = cx.expr_isize(span, 0); - cs_fold(false, - |cx, span, subexpr, field, _| { - cx.expr_binary(span, ast::BinOpKind::Add, subexpr, - cx.expr_method_call(span, field, - ast::Ident::from_str("total_sum"), vec![])) - }, - zero, - box |cx, span, _, _| { cx.span_bug(span, "wtf??"); }, - cx, span, substr) - }), - }, - ], - }; - - trait_def.expand(cx, mitem, item, push) -} diff --git a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs deleted file mode 100644 index ac8fff4f6bfad..0000000000000 --- a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs +++ /dev/null @@ -1,10 +0,0 @@ -// aux-build:custom-derive-partial-eq.rs -// ignore-stage1 -#![feature(plugin)] -#![plugin(custom_derive_partial_eq)] -#![allow(unused)] - -#[derive_CustomPartialEq] // Check that this is not a stability error. -enum E { V1, V2 } - -fn main() {} diff --git a/src/test/run-pass-fulldeps/derive-totalsum-attr.rs b/src/test/run-pass-fulldeps/derive-totalsum-attr.rs deleted file mode 100644 index 38eaa71dd6aba..0000000000000 --- a/src/test/run-pass-fulldeps/derive-totalsum-attr.rs +++ /dev/null @@ -1,64 +0,0 @@ -// aux-build:custom-derive-plugin-attr.rs -// ignore-stage1 - -#![feature(plugin, rustc_attrs)] -#![plugin(custom_derive_plugin_attr)] - -trait TotalSum { - fn total_sum(&self) -> isize; -} - -impl TotalSum for isize { - fn total_sum(&self) -> isize { - *self - } -} - -struct Seven; - -impl TotalSum for Seven { - fn total_sum(&self) -> isize { - 7 - } -} - -#[rustc_derive_TotalSum] -struct Foo { - seven: Seven, - bar: Bar, - baz: isize, - #[ignore] - nan: NaN, -} - -#[rustc_derive_TotalSum] -struct Bar { - quux: isize, - bleh: isize, - #[ignore] - nan: NaN2 -} - -struct NaN; - -impl TotalSum for NaN { - fn total_sum(&self) -> isize { - panic!(); - } -} - -struct NaN2; - -pub fn main() { - let v = Foo { - seven: Seven, - bar: Bar { - quux: 9, - bleh: 3, - nan: NaN2 - }, - baz: 80, - nan: NaN - }; - assert_eq!(v.total_sum(), 99); -} diff --git a/src/test/run-pass-fulldeps/derive-totalsum.rs b/src/test/run-pass-fulldeps/derive-totalsum.rs deleted file mode 100644 index 2b0bb51d90aec..0000000000000 --- a/src/test/run-pass-fulldeps/derive-totalsum.rs +++ /dev/null @@ -1,49 +0,0 @@ -// aux-build:custom-derive-plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(custom_derive_plugin)] - -trait TotalSum { - fn total_sum(&self) -> isize; -} - -impl TotalSum for isize { - fn total_sum(&self) -> isize { - *self - } -} - -struct Seven; - -impl TotalSum for Seven { - fn total_sum(&self) -> isize { - 7 - } -} - -#[derive_TotalSum] -struct Foo { - seven: Seven, - bar: Bar, - baz: isize, -} - -#[derive_TotalSum] -struct Bar { - quux: isize, - bleh: isize, -} - - -pub fn main() { - let v = Foo { - seven: Seven, - bar: Bar { - quux: 9, - bleh: 3, - }, - baz: 80, - }; - assert_eq!(v.total_sum(), 99); -} diff --git a/src/test/run-pass-fulldeps/issue-40663.rs b/src/test/run-pass-fulldeps/issue-40663.rs deleted file mode 100644 index 133f6302bde57..0000000000000 --- a/src/test/run-pass-fulldeps/issue-40663.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![allow(dead_code)] -// aux-build:custom-derive-plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(custom_derive_plugin)] - -#[derive_Nothing] -#[derive_Nothing] -#[derive_Nothing] -struct S; - -fn main() {} From cc17dbb37bd0d71aebb77691e60f7c43289b4cf5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 6 Jun 2019 23:21:44 +0300 Subject: [PATCH 04/20] syntax: Use `MultiItemModifier` for built-in derives --- src/libsyntax/ext/base.rs | 7 +--- src/libsyntax/ext/expand.rs | 40 +++++++++---------- src/libsyntax_ext/deriving/bounds.rs | 11 ++--- src/libsyntax_ext/deriving/clone.rs | 6 +-- src/libsyntax_ext/deriving/cmp/eq.rs | 6 +-- src/libsyntax_ext/deriving/cmp/ord.rs | 6 +-- src/libsyntax_ext/deriving/cmp/partial_eq.rs | 6 +-- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 6 +-- src/libsyntax_ext/deriving/debug.rs | 6 +-- src/libsyntax_ext/deriving/decodable.rs | 20 +++++----- src/libsyntax_ext/deriving/default.rs | 6 +-- src/libsyntax_ext/deriving/encodable.rs | 20 +++++----- src/libsyntax_ext/deriving/generic/mod.rs | 18 ++++----- src/libsyntax_ext/deriving/hash.rs | 7 ++-- src/libsyntax_ext/deriving/mod.rs | 2 +- 15 files changed, 82 insertions(+), 85 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1a716c3faef1d..d45895c8d237e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,6 +1,6 @@ pub use SyntaxExtension::*; -use crate::ast::{self, Attribute, Name, PatKind, MetaItem}; +use crate::ast::{self, Attribute, Name, PatKind}; use crate::attr::HasAttrs; use crate::source_map::{SourceMap, Spanned, respan}; use crate::edition::Edition; @@ -516,9 +516,6 @@ impl MacResult for DummyResult { } } -pub type BuiltinDeriveFn = - for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)); - /// Represents different kinds of macro invocations that can be resolved. #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum MacroKind { @@ -604,7 +601,7 @@ pub enum SyntaxExtension { Vec /* inert attribute names */, Edition), /// An attribute-like procedural macro that derives a builtin trait. - BuiltinDerive(BuiltinDeriveFn), + BuiltinDerive(Box), /// A declarative macro, e.g., `macro m() {}`. DeclMacro { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 7d2928ef1807b..b314067fab664 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -893,29 +893,29 @@ impl<'a, 'b> MacroExpander<'a, 'b> { edition: ext.edition(self.cx.parse_sess.edition), }; - match *ext { - ProcMacroDerive(ref ext, ..) => { - invoc.expansion_data.mark.set_expn_info(expn_info); - let span = span.with_ctxt(self.cx.backtrace()); - let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this - path: Path::from_ident(Ident::invalid()), - span: DUMMY_SP, - node: ast::MetaItemKind::Word, + match ext { + ProcMacroDerive(expander, ..) | BuiltinDerive(expander) => { + let meta = match ext { + ProcMacroDerive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this + path: Path::from_ident(Ident::invalid()), + span: DUMMY_SP, + node: ast::MetaItemKind::Word, + }, + _ => { + expn_info.allow_internal_unstable = Some(vec![ + sym::rustc_attrs, + Symbol::intern("derive_clone_copy"), + Symbol::intern("derive_eq"), + // RustcDeserialize and RustcSerialize + Symbol::intern("libstd_sys_internals"), + ].into()); + attr.meta()? + } }; - let items = ext.expand(self.cx, span, &dummy, item); - Some(invoc.fragment_kind.expect_from_annotatables(items)) - } - BuiltinDerive(func) => { - expn_info.allow_internal_unstable = Some(vec![ - sym::rustc_attrs, - Symbol::intern("derive_clone_copy"), - Symbol::intern("derive_eq"), - Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize - ].into()); + invoc.expansion_data.mark.set_expn_info(expn_info); let span = span.with_ctxt(self.cx.backtrace()); - let mut items = Vec::new(); - func(self.cx, span, &attr.meta()?, &item, &mut |a| items.push(a)); + let items = expander.expand(self.cx, span, &meta, item); Some(invoc.fragment_kind.expect_from_annotatables(items)) } _ => { diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs index c7b805e0bdca6..ff700793a7b45 100644 --- a/src/libsyntax_ext/deriving/bounds.rs +++ b/src/libsyntax_ext/deriving/bounds.rs @@ -9,16 +9,17 @@ use syntax_pos::Span; pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt<'_>, span: Span, _: &MetaItem, - _: &Annotatable, - _: &mut dyn FnMut(Annotatable)) { + _: Annotatable) + -> Vec { cx.span_err(span, "this unsafe trait should be implemented explicitly"); + Vec::new() } pub fn expand_deriving_copy(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + ref item: Annotatable) + -> Vec { let trait_def = TraitDef { span, attributes: Vec::new(), @@ -31,5 +32,5 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt<'_>, associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push); + trait_def.expand(cx, mitem, item) } diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index b3b6328e2ca73..efd1333abbc66 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -13,8 +13,8 @@ use syntax_pos::Span; pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + ref item: Annotatable) + -> Vec { // check if we can use a short form // // the short form is `fn clone(&self) -> Self { *self }` @@ -100,7 +100,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>, associated_types: Vec::new(), }; - trait_def.expand_ext(cx, mitem, item, push, is_shallow) + trait_def.expand_ext(cx, mitem, item, is_shallow) } fn cs_clone_shallow(name: &str, diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 1d981e0ff7906..f16317d9ab59b 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -12,8 +12,8 @@ use syntax_pos::Span; pub fn expand_deriving_eq(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + ref item: Annotatable) + -> Vec { let inline = cx.meta_word(span, sym::inline); let hidden = cx.meta_list_item_word(span, sym::hidden); let doc = cx.meta_list(span, sym::doc, vec![hidden]); @@ -41,7 +41,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt<'_>, }], associated_types: Vec::new(), }; - trait_def.expand_ext(cx, mitem, item, push, true) + trait_def.expand_ext(cx, mitem, item, true) } fn cs_total_eq_assert(cx: &mut ExtCtxt<'_>, diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index b25a9e4c50fbe..84bb02d49c4e6 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -12,8 +12,8 @@ use syntax_pos::Span; pub fn expand_deriving_ord(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + ref item: Annotatable) + -> Vec { let inline = cx.meta_word(span, sym::inline); let attrs = vec![cx.attribute(span, inline)]; let trait_def = TraitDef { @@ -40,7 +40,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt<'_>, associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item) } diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index 6172f27261ecf..f56ee90ebad68 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -12,8 +12,8 @@ use syntax_pos::Span; pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + ref item: Annotatable) + -> Vec { // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different fn cs_op(cx: &mut ExtCtxt<'_>, @@ -99,5 +99,5 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>, methods, associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item) } diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 3980741f252dd..e02d1522c3955 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -14,8 +14,8 @@ use syntax_pos::Span; pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + ref item: Annotatable) + -> Vec { macro_rules! md { ($name:expr, $op:expr, $equal:expr) => { { let inline = cx.meta_word(span, sym::inline); @@ -83,7 +83,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt<'_>, methods, associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item) } #[derive(Copy, Clone)] diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index 44ddbb98809b4..ef2051cd03f18 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -15,8 +15,8 @@ use syntax_pos::{DUMMY_SP, Span}; pub fn expand_deriving_debug(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + ref item: Annotatable) + -> Vec { // &mut ::std::fmt::Formatter let fmtr = Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), Borrowed(None, ast::Mutability::Mutable)); @@ -44,7 +44,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt<'_>, }], associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item) } /// We use the debug builders to do the heavy lifting here diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index d773f3ff7bcc5..90fc43783ab83 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -16,26 +16,26 @@ use syntax_pos::Span; pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { - expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize") + item: Annotatable) + -> Vec { + expand_deriving_decodable_imp(cx, span, mitem, item, "rustc_serialize") } pub fn expand_deriving_decodable(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + item: Annotatable) + -> Vec { warn_if_deprecated(cx, span, "Decodable"); - expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize") + expand_deriving_decodable_imp(cx, span, mitem, item, "serialize") } fn expand_deriving_decodable_imp(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - krate: &'static str) { + ref item: Annotatable, + krate: &'static str) + -> Vec { let typaram = &*deriving::hygienic_type_parameter(item, "__D"); let trait_def = TraitDef { @@ -76,7 +76,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt<'_>, associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item) } fn decodable_substructure(cx: &mut ExtCtxt<'_>, diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index fd8e87e2fefd1..48bd753e7b16e 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -13,8 +13,8 @@ use syntax_pos::Span; pub fn expand_deriving_default(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + ref item: Annotatable) + -> Vec { let inline = cx.meta_word(span, sym::inline); let attrs = vec![cx.attribute(span, inline)]; let trait_def = TraitDef { @@ -40,7 +40,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt<'_>, }], associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item) } fn default_substructure(cx: &mut ExtCtxt<'_>, diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index faaedba3e77dd..1893fb13460cb 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -97,26 +97,26 @@ use syntax_pos::Span; pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { - expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize") + item: Annotatable) + -> Vec { + expand_deriving_encodable_imp(cx, span, mitem, item, "rustc_serialize") } pub fn expand_deriving_encodable(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { + item: Annotatable) + -> Vec { warn_if_deprecated(cx, span, "Encodable"); - expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize") + expand_deriving_encodable_imp(cx, span, mitem, item, "serialize") } fn expand_deriving_encodable_imp(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - krate: &'static str) { + ref item: Annotatable, + krate: &'static str) + -> Vec { let typaram = &*deriving::hygienic_type_parameter(item, "__S"); let trait_def = TraitDef { @@ -159,7 +159,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt<'_>, associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item) } fn encodable_substructure(cx: &mut ExtCtxt<'_>, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index ffec667aba5d3..b97ee09eeb6ee 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -388,17 +388,17 @@ impl<'a> TraitDef<'a> { pub fn expand(self, cx: &mut ExtCtxt<'_>, mitem: &ast::MetaItem, - item: &'a Annotatable, - push: &mut dyn FnMut(Annotatable)) { - self.expand_ext(cx, mitem, item, push, false); + item: &'a Annotatable) + -> Vec { + self.expand_ext(cx, mitem, item, false) } pub fn expand_ext(self, cx: &mut ExtCtxt<'_>, mitem: &ast::MetaItem, item: &'a Annotatable, - push: &mut dyn FnMut(Annotatable), - from_scratch: bool) { + from_scratch: bool) + -> Vec { match *item { Annotatable::Item(ref item) => { let is_packed = item.attrs.iter().any(|attr| { @@ -422,7 +422,7 @@ impl<'a> TraitDef<'a> { // Non-ADT derive is an error, but it should have been // set earlier; see // libsyntax/ext/expand.rs:MacroExpander::expand() - return; + return Vec::new(); } }; let is_always_copy = @@ -453,7 +453,7 @@ impl<'a> TraitDef<'a> { } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); - return; + return Vec::new(); } } _ => unreachable!(), @@ -468,13 +468,13 @@ impl<'a> TraitDef<'a> { .contains(&a.name_or_empty()) }) .cloned()); - push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) + vec![Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))] } _ => { // Non-Item derive is an error, but it should have been // set earlier; see // libsyntax/ext/expand.rs:MacroExpander::expand() - return; + Vec::new() } } } diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index e7f99d4578226..752bf774c8015 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -12,9 +12,8 @@ use syntax_pos::Span; pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable)) { - + ref item: Annotatable) + -> Vec { let path = Path::new_(pathvec_std!(cx, hash::Hash), None, vec![], PathKind::Std); let typaram = &*deriving::hygienic_type_parameter(item, "__H"); @@ -48,7 +47,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>, associated_types: Vec::new(), }; - hash_trait_def.expand(cx, mitem, item, push); + hash_trait_def.expand(cx, mitem, item) } fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P { diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index ac41f30e6b39f..d6d16d0dbd155 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -55,7 +55,7 @@ macro_rules! derive_traits { $( resolver.add_builtin( ast::Ident::with_empty_ctxt(Symbol::intern($name)), - Lrc::new(SyntaxExtension::BuiltinDerive($func)) + Lrc::new(SyntaxExtension::BuiltinDerive(Box::new($func))) ); )* } From fa48a02c0a743e0963d51162b1eb2dba5d4dd190 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 7 Jun 2019 00:37:47 +0300 Subject: [PATCH 05/20] Remove `SyntaxExtension::DeclMacro` It's a less powerful duplicate of `SyntaxExtension::NormalTT` --- src/librustc_plugin/registry.rs | 31 ++--- src/librustc_resolve/macros.rs | 3 +- .../passes/collect_intra_doc_links.rs | 2 +- src/libsyntax/ext/base.rs | 18 +-- src/libsyntax/ext/expand.rs | 11 +- src/libsyntax/ext/tt/macro_rules.rs | 109 +++++++++--------- src/libsyntax_ext/lib.rs | 4 + .../auxiliary/plugin-args.rs | 2 + .../ui/macros/nonterminal-matching.stderr | 3 + 9 files changed, 79 insertions(+), 104 deletions(-) diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 967fdcd2e7d41..f4b4bcb043c42 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -6,6 +6,7 @@ use rustc::util::nodemap::FxHashMap; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; use syntax::ext::base::MacroExpanderFn; +use syntax::ext::hygiene::Transparency; use syntax::symbol::{Symbol, sym}; use syntax::ast; use syntax::feature_gate::AttributeType; @@ -84,33 +85,14 @@ impl<'a> Registry<'a> { /// Register a syntax extension of any kind. /// /// This is the most general hook into `libsyntax`'s expansion behavior. - pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) { + pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: SyntaxExtension) { if name == sym::macro_rules { panic!("user-defined macros may not be named `macro_rules`"); } - self.syntax_exts.push((name, match extension { - NormalTT { - expander, - def_info: _, - allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - unstable_feature, - edition, - } => { - let nid = ast::CRATE_NODE_ID; - NormalTT { - expander, - def_info: Some((nid, self.krate_span)), - allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - unstable_feature, - edition, - } - } - _ => extension, - })); + if let NormalTT { def_info: ref mut def_info @ None, .. } = extension { + *def_info = Some((ast::CRATE_NODE_ID, self.krate_span)); + } + self.syntax_exts.push((name, extension)); } /// Register a macro of the usual kind. @@ -122,6 +104,7 @@ impl<'a> Registry<'a> { self.register_syntax_extension(Symbol::intern(name), NormalTT { expander: Box::new(expander), def_info: None, + transparency: Transparency::SemiTransparent, allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 08ab5b8532522..b5af7bb74a644 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -242,8 +242,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn check_unused_macros(&self) { for did in self.unused_macros.iter() { let id_span = match *self.macro_map[did] { - SyntaxExtension::NormalTT { def_info, .. } | - SyntaxExtension::DeclMacro { def_info, .. } => def_info, + SyntaxExtension::NormalTT { def_info, .. } => def_info, _ => None, }; if let Some((id, span)) = id_span { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 860ea18a58ad0..1e824e6fdfba0 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -433,7 +433,7 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { if let Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) = res { // skip proc-macro stubs, they'll cause `get_macro` to crash } else { - if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(res) { + if let SyntaxExtension::NormalTT { .. } = *resolver.get_macro(res) { return Some(res.map_id(|_| panic!("unexpected id"))); } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d45895c8d237e..bcee3e5a40bad 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -576,6 +576,7 @@ pub enum SyntaxExtension { NormalTT { expander: Box, def_info: Option<(ast::NodeId, Span)>, + transparency: Transparency, /// Whether the contents of the macro can /// directly use `#[unstable]` things. /// @@ -602,21 +603,12 @@ pub enum SyntaxExtension { /// An attribute-like procedural macro that derives a builtin trait. BuiltinDerive(Box), - - /// A declarative macro, e.g., `macro m() {}`. - DeclMacro { - expander: Box, - def_info: Option<(ast::NodeId, Span)>, - is_transparent: bool, - edition: Edition, - } } impl SyntaxExtension { /// Returns which kind of macro calls this syntax extension. pub fn kind(&self) -> MacroKind { match *self { - SyntaxExtension::DeclMacro { .. } | SyntaxExtension::NormalTT { .. } | SyntaxExtension::ProcMacro { .. } => MacroKind::Bang, @@ -632,19 +624,19 @@ impl SyntaxExtension { pub fn default_transparency(&self) -> Transparency { match *self { + SyntaxExtension::NormalTT { transparency, .. } => transparency, SyntaxExtension::ProcMacro { .. } | SyntaxExtension::AttrProcMacro(..) | SyntaxExtension::ProcMacroDerive(..) | - SyntaxExtension::DeclMacro { is_transparent: false, .. } => Transparency::Opaque, - SyntaxExtension::DeclMacro { is_transparent: true, .. } => Transparency::Transparent, - _ => Transparency::SemiTransparent, + SyntaxExtension::NonMacroAttr { .. } => Transparency::Opaque, + SyntaxExtension::MultiModifier(..) | + SyntaxExtension::BuiltinDerive(..) => Transparency::SemiTransparent, } } pub fn edition(&self, default_edition: Edition) -> Edition { match *self { SyntaxExtension::NormalTT { edition, .. } | - SyntaxExtension::DeclMacro { edition, .. } | SyntaxExtension::ProcMacro { edition, .. } | SyntaxExtension::AttrProcMacro(.., edition) | SyntaxExtension::ProcMacroDerive(.., edition) => edition, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b314067fab664..8b49b9b028441 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -747,16 +747,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let opt_expanded = match *ext { - DeclMacro { ref expander, def_info, edition, .. } => { - if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s), - None, false, false, None, - edition) { - dummy_span - } else { - kind.make_from(expander.expand(self.cx, span, mac.node.stream(), None)) - } - } - NormalTT { ref expander, def_info, @@ -765,6 +755,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { local_inner_macros, unstable_feature, edition, + .. } => { if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s), allow_internal_unstable.clone(), diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 285c88357a6a8..8c4072db27b17 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -3,6 +3,7 @@ use crate::edition::Edition; use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; use crate::ext::base::{NormalTT, TTMacroExpander}; use crate::ext::expand::{AstFragment, AstFragmentKind}; +use crate::ext::hygiene::Transparency; use crate::ext::tt::macro_parser::{Success, Error, Failure}; use crate::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use crate::ext::tt::macro_parser::{parse, parse_failure_msg}; @@ -375,65 +376,65 @@ pub fn compile( valid, }); - if body.legacy { - let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable) - .map(|attr| attr - .meta_item_list() - .map(|list| list.iter() - .filter_map(|it| { - let name = it.ident().map(|ident| ident.name); - if name.is_none() { - sess.span_diagnostic.span_err(it.span(), - "allow internal unstable expects feature names") - } - name - }) - .collect::>().into() - ) - .unwrap_or_else(|| { - sess.span_diagnostic.span_warn( - attr.span, "allow_internal_unstable expects list of feature names. In the \ - future this will become a hard error. Please use `allow_internal_unstable(\ - foo, bar)` to only allow the `foo` and `bar` features", - ); - vec![sym::allow_internal_unstable_backcompat_hack].into() + let transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) { + Transparency::Transparent + } else if body.legacy { + Transparency::SemiTransparent + } else { + Transparency::Opaque + }; + + let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable) + .map(|attr| attr + .meta_item_list() + .map(|list| list.iter() + .filter_map(|it| { + let name = it.ident().map(|ident| ident.name); + if name.is_none() { + sess.span_diagnostic.span_err(it.span(), + "allow internal unstable expects feature names") + } + name }) - ); - let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe); - let mut local_inner_macros = false; - if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) { - if let Some(l) = macro_export.meta_item_list() { - local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); - } - } + .collect::>().into() + ) + .unwrap_or_else(|| { + sess.span_diagnostic.span_warn( + attr.span, "allow_internal_unstable expects list of feature names. In the \ + future this will become a hard error. Please use `allow_internal_unstable(\ + foo, bar)` to only allow the `foo` and `bar` features", + ); + vec![sym::allow_internal_unstable_backcompat_hack].into() + }) + ); - let unstable_feature = attr::find_stability(&sess, - &def.attrs, def.span).and_then(|stability| { - if let attr::StabilityLevel::Unstable { issue, .. } = stability.level { - Some((stability.feature, issue)) - } else { - None - } - }); - - NormalTT { - expander, - def_info: Some((def.id, def.span)), - allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, - unstable_feature, - edition, + let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe); + + let mut local_inner_macros = false; + if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) { + if let Some(l) = macro_export.meta_item_list() { + local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); } - } else { - let is_transparent = attr::contains_name(&def.attrs, sym::rustc_transparent_macro); + } - SyntaxExtension::DeclMacro { - expander, - def_info: Some((def.id, def.span)), - is_transparent, - edition, + let unstable_feature = attr::find_stability(&sess, + &def.attrs, def.span).and_then(|stability| { + if let attr::StabilityLevel::Unstable { issue, .. } = stability.level { + Some((stability.feature, issue)) + } else { + None } + }); + + NormalTT { + expander, + def_info: Some((def.id, def.span)), + transparency, + allow_internal_unstable, + allow_internal_unsafe, + local_inner_macros, + unstable_feature, + edition, } } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index fc00154427501..7d6abd14a4a00 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -42,6 +42,7 @@ pub mod proc_macro_impl; use rustc_data_structures::sync::Lrc; use syntax::ast; use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension, MultiModifier}; +use syntax::ext::hygiene::Transparency; use syntax::edition::Edition; use syntax::symbol::{sym, Symbol}; @@ -59,6 +60,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, NormalTT { expander: Box::new($f as MacroExpanderFn), def_info: None, + transparency: Transparency::SemiTransparent, allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, @@ -102,6 +104,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, NormalTT { expander: Box::new(format::expand_format_args), def_info: None, + transparency: Transparency::SemiTransparent, allow_internal_unstable: Some(vec![sym::fmt_internals].into()), allow_internal_unsafe: false, local_inner_macros: false, @@ -112,6 +115,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, NormalTT { expander: Box::new(format::expand_format_args_nl), def_info: None, + transparency: Transparency::SemiTransparent, allow_internal_unstable: Some(vec![sym::fmt_internals].into()), allow_internal_unsafe: false, local_inner_macros: false, diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs index 096701bd9b3ed..cf12b80848436 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs @@ -13,6 +13,7 @@ use syntax::ast; use syntax::ext::hygiene; use syntax::ext::build::AstBuilder; use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT}; +use syntax::ext::hygiene::Transparency; use syntax::print::pprust; use syntax::ptr::P; use syntax::symbol::Symbol; @@ -43,6 +44,7 @@ pub fn plugin_registrar(reg: &mut Registry) { NormalTT { expander: Box::new(Expander { args: args, }), def_info: None, + transparency: Transparency::SemiTransparent, allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, diff --git a/src/test/ui/macros/nonterminal-matching.stderr b/src/test/ui/macros/nonterminal-matching.stderr index 5fba8002e1c48..93cc97d45830b 100644 --- a/src/test/ui/macros/nonterminal-matching.stderr +++ b/src/test/ui/macros/nonterminal-matching.stderr @@ -1,6 +1,9 @@ error: no rules expected the token `enum E { }` --> $DIR/nonterminal-matching.rs:19:10 | +LL | macro n(a $nt_item b) { + | --------------------- when calling this macro +... LL | n!(a $nt_item b); | ^^^^^^^^ no rules expected this token in macro call ... From a9397fd0d5eede4bbc0ada94bf92657ca8084cb3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 7 Jun 2019 01:59:27 +0300 Subject: [PATCH 06/20] syntax: Improve documentation of `SyntaxExtension` --- src/libsyntax/ext/base.rs | 90 +++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 36 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index bcee3e5a40bad..4e5971a075f10 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -549,60 +549,78 @@ 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 { mark_used: bool }, - - /// A syntax extension that is attached to an item and modifies it - /// in-place. Also allows decoration, i.e., creating new items. - MultiModifier(Box), - - /// A function-like procedural macro. TokenStream -> TokenStream. + /// A token-based function-like macro. ProcMacro { + /// An expander with signature TokenStream -> TokenStream. expander: Box, - /// Whitelist of unstable features that are treated as stable inside this macro + /// Whitelist of unstable features that are treated as stable inside this macro. allow_internal_unstable: Option>, + /// Edition of the crate in which this macro is defined. edition: Edition, }, - /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream. - /// The first TokenSteam is the attribute, the second is the annotated item. - /// Allows modification of the input items and adding new items, similar to - /// MultiModifier, but uses TokenStreams, rather than AST nodes. - AttrProcMacro(Box, Edition), - - /// A normal, function-like syntax extension. - /// - /// `bytes!` is a `NormalTT`. + /// An AST-based function-like macro. NormalTT { + /// An expander with signature TokenStream -> AST. expander: Box, + /// Some info about the macro's definition point. def_info: Option<(ast::NodeId, Span)>, + /// Hygienic properties of identifiers produced by this macro. transparency: Transparency, - /// Whether the contents of the macro can - /// directly use `#[unstable]` things. - /// - /// Only allows things that require a feature gate in the given whitelist + /// Whitelist of unstable features that are treated as stable inside this macro. allow_internal_unstable: Option>, - /// Whether the contents of the macro can use `unsafe` - /// without triggering the `unsafe_code` lint. + /// Suppresses the `unsafe_code` lint for code produced by this macro. allow_internal_unsafe: bool, - /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) - /// for a given macro. + /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. local_inner_macros: bool, - /// The macro's feature name if it is unstable, and the stability feature + /// The macro's feature name and tracking issue number if it is unstable. unstable_feature: Option<(Symbol, u32)>, - /// Edition of the crate in which the macro is defined + /// Edition of the crate in which this macro is defined. edition: Edition, }, - /// An attribute-like procedural macro. TokenStream -> TokenStream. - /// The input is the annotated item. - /// Allows generating code to implement a Trait for a given struct - /// or enum item. - ProcMacroDerive(Box, - Vec /* inert attribute names */, Edition), + /// A token-based attribute macro. + AttrProcMacro( + /// An expander with signature (TokenStream, TokenStream) -> TokenStream. + /// The first TokenSteam is the attribute itself, the second is the annotated item. + /// The produced TokenSteam replaces the input TokenSteam. + Box, + /// Edition of the crate in which this macro is defined. + Edition, + ), + + /// An AST-based attribute macro. + MultiModifier( + /// An expander with signature (AST, AST) -> AST. + /// The first AST fragment is the attribute itself, the second is the annotated item. + /// The produced AST fragment replaces the input AST fragment. + Box, + ), + + /// A trivial attribute "macro" that does nothing, + /// only keeps the attribute and marks it as known. + NonMacroAttr { + /// Suppresses the `unused_attributes` lint for this attribute. + mark_used: bool, + }, - /// An attribute-like procedural macro that derives a builtin trait. - BuiltinDerive(Box), + /// A token-based derive macro. + ProcMacroDerive( + /// An expander with signature TokenStream -> TokenStream (not yet). + /// The produced TokenSteam is appended to the input TokenSteam. + Box, + /// Names of helper attributes registered by this macro. + Vec, + /// Edition of the crate in which this macro is defined. + Edition, + ), + + /// An AST-based derive macro. + BuiltinDerive( + /// An expander with signature AST -> AST. + /// The produced AST fragment is appended to the input AST fragment. + Box, + ), } impl SyntaxExtension { From 48d2c0bfd48cd29a15605e6c733ccad3414b0eb2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 7 Jun 2019 02:30:01 +0300 Subject: [PATCH 07/20] syntax: Rename variants of `SyntaxExtension` for consistency --- src/librustc_metadata/creader.rs | 6 +- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_plugin/registry.rs | 8 +-- src/librustc_resolve/macros.rs | 4 +- src/librustdoc/clean/inline.rs | 2 +- .../passes/collect_intra_doc_links.rs | 2 +- src/libsyntax/ext/base.rs | 55 +++++++++---------- src/libsyntax/ext/expand.rs | 26 +++++---- src/libsyntax/ext/tt/macro_rules.rs | 5 +- src/libsyntax_ext/deriving/mod.rs | 2 +- src/libsyntax_ext/lib.rs | 15 ++--- .../auxiliary/plugin-args.rs | 8 +-- 12 files changed, 65 insertions(+), 70 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 991bebc647d0f..7ffba41e2569a 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -614,7 +614,7 @@ impl<'a> CrateLoader<'a> { match decl { ProcMacro::CustomDerive { trait_name, attributes, client } => { let attrs = attributes.iter().cloned().map(Symbol::intern).collect::>(); - (trait_name, SyntaxExtension::ProcMacroDerive( + (trait_name, SyntaxExtension::Derive( Box::new(ProcMacroDerive { client, attrs: attrs.clone(), @@ -624,13 +624,13 @@ impl<'a> CrateLoader<'a> { )) } ProcMacro::Attr { name, client } => { - (name, SyntaxExtension::AttrProcMacro( + (name, SyntaxExtension::Attr( Box::new(AttrProcMacro { client }), root.edition, )) } ProcMacro::Bang { name, client } => { - (name, SyntaxExtension::ProcMacro { + (name, SyntaxExtension::Bang { expander: Box::new(BangProcMacro { client }), allow_internal_unstable: None, edition: root.edition, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index db452bb4ac7bc..35faa1df82b84 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -430,7 +430,7 @@ impl cstore::CStore { use syntax_ext::proc_macro_impl::BangProcMacro; let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); - let ext = SyntaxExtension::ProcMacro { + let ext = SyntaxExtension::Bang { expander: Box::new(BangProcMacro { client }), allow_internal_unstable: Some(vec![sym::proc_macro_def_site].into()), edition: data.root.edition, diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index f4b4bcb043c42..dd5e42684c427 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -4,7 +4,7 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; -use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; +use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension}; use syntax::ext::base::MacroExpanderFn; use syntax::ext::hygiene::Transparency; use syntax::symbol::{Symbol, sym}; @@ -89,7 +89,7 @@ impl<'a> Registry<'a> { if name == sym::macro_rules { panic!("user-defined macros may not be named `macro_rules`"); } - if let NormalTT { def_info: ref mut def_info @ None, .. } = extension { + if let SyntaxExtension::LegacyBang { def_info: ref mut def_info @ None, .. } = extension { *def_info = Some((ast::CRATE_NODE_ID, self.krate_span)); } self.syntax_exts.push((name, extension)); @@ -98,10 +98,10 @@ impl<'a> Registry<'a> { /// Register a macro of the usual kind. /// /// This is a convenience wrapper for `register_syntax_extension`. - /// It builds for you a `NormalTT` that calls `expander`, + /// It builds for you a `SyntaxExtension::LegacyBang` that calls `expander`, /// and also takes care of interning the macro's name. pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) { - self.register_syntax_extension(Symbol::intern(name), NormalTT { + self.register_syntax_extension(Symbol::intern(name), SyntaxExtension::LegacyBang { expander: Box::new(expander), def_info: None, transparency: Transparency::SemiTransparent, diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index b5af7bb74a644..2369bddf4f75f 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -242,7 +242,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn check_unused_macros(&self) { for did in self.unused_macros.iter() { let id_span = match *self.macro_map[did] { - SyntaxExtension::NormalTT { def_info, .. } => def_info, + SyntaxExtension::LegacyBang { def_info, .. } => def_info, _ => None, }; if let Some((id, span)) = id_span { @@ -586,7 +586,7 @@ impl<'a> Resolver<'a> { match self.resolve_macro_to_res(derive, MacroKind::Derive, &parent_scope, true, force) { Ok((_, ext)) => { - if let SyntaxExtension::ProcMacroDerive(_, helpers, _) = &*ext { + if let SyntaxExtension::Derive(_, helpers, _) = &*ext { if helpers.contains(&ident.name) { let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 15108a7dbb91c..5a5540e7e3855 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -471,7 +471,7 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE } LoadedMacro::ProcMacro(ext) => { let helpers = match &*ext { - &SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) } + &SyntaxExtension::Derive(_, ref syms, ..) => { syms.clean(cx) } _ => Vec::new(), }; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1e824e6fdfba0..7fbfc3e1fc0f4 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -433,7 +433,7 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { if let Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) = res { // skip proc-macro stubs, they'll cause `get_macro` to crash } else { - if let SyntaxExtension::NormalTT { .. } = *resolver.get_macro(res) { + if let SyntaxExtension::LegacyBang { .. } = *resolver.get_macro(res) { return Some(res.map_id(|_| panic!("unexpected id"))); } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 4e5971a075f10..045e45071d1c6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,5 +1,3 @@ -pub use SyntaxExtension::*; - use crate::ast::{self, Attribute, Name, PatKind}; use crate::attr::HasAttrs; use crate::source_map::{SourceMap, Spanned, respan}; @@ -550,7 +548,7 @@ impl MacroKind { /// An enum representing the different kinds of syntax extensions. pub enum SyntaxExtension { /// A token-based function-like macro. - ProcMacro { + Bang { /// An expander with signature TokenStream -> TokenStream. expander: Box, /// Whitelist of unstable features that are treated as stable inside this macro. @@ -560,7 +558,7 @@ pub enum SyntaxExtension { }, /// An AST-based function-like macro. - NormalTT { + LegacyBang { /// An expander with signature TokenStream -> AST. expander: Box, /// Some info about the macro's definition point. @@ -580,7 +578,7 @@ pub enum SyntaxExtension { }, /// A token-based attribute macro. - AttrProcMacro( + Attr( /// An expander with signature (TokenStream, TokenStream) -> TokenStream. /// The first TokenSteam is the attribute itself, the second is the annotated item. /// The produced TokenSteam replaces the input TokenSteam. @@ -590,7 +588,7 @@ pub enum SyntaxExtension { ), /// An AST-based attribute macro. - MultiModifier( + LegacyAttr( /// An expander with signature (AST, AST) -> AST. /// The first AST fragment is the attribute itself, the second is the annotated item. /// The produced AST fragment replaces the input AST fragment. @@ -605,7 +603,7 @@ pub enum SyntaxExtension { }, /// A token-based derive macro. - ProcMacroDerive( + Derive( /// An expander with signature TokenStream -> TokenStream (not yet). /// The produced TokenSteam is appended to the input TokenSteam. Box, @@ -616,7 +614,7 @@ pub enum SyntaxExtension { ), /// An AST-based derive macro. - BuiltinDerive( + LegacyDerive( /// An expander with signature AST -> AST. /// The produced AST fragment is appended to the input AST fragment. Box, @@ -627,41 +625,38 @@ impl SyntaxExtension { /// Returns which kind of macro calls this syntax extension. pub fn kind(&self) -> MacroKind { match *self { - SyntaxExtension::NormalTT { .. } | - SyntaxExtension::ProcMacro { .. } => - MacroKind::Bang, - SyntaxExtension::NonMacroAttr { .. } | - SyntaxExtension::MultiModifier(..) | - SyntaxExtension::AttrProcMacro(..) => - MacroKind::Attr, - SyntaxExtension::ProcMacroDerive(..) | - SyntaxExtension::BuiltinDerive(..) => - MacroKind::Derive, + SyntaxExtension::Bang { .. } | + SyntaxExtension::LegacyBang { .. } => MacroKind::Bang, + SyntaxExtension::Attr(..) | + SyntaxExtension::LegacyAttr(..) | + SyntaxExtension::NonMacroAttr { .. } => MacroKind::Attr, + SyntaxExtension::Derive(..) | + SyntaxExtension::LegacyDerive(..) => MacroKind::Derive, } } pub fn default_transparency(&self) -> Transparency { match *self { - SyntaxExtension::NormalTT { transparency, .. } => transparency, - SyntaxExtension::ProcMacro { .. } | - SyntaxExtension::AttrProcMacro(..) | - SyntaxExtension::ProcMacroDerive(..) | + SyntaxExtension::LegacyBang { transparency, .. } => transparency, + SyntaxExtension::Bang { .. } | + SyntaxExtension::Attr(..) | + SyntaxExtension::Derive(..) | SyntaxExtension::NonMacroAttr { .. } => Transparency::Opaque, - SyntaxExtension::MultiModifier(..) | - SyntaxExtension::BuiltinDerive(..) => Transparency::SemiTransparent, + SyntaxExtension::LegacyAttr(..) | + SyntaxExtension::LegacyDerive(..) => Transparency::SemiTransparent, } } pub fn edition(&self, default_edition: Edition) -> Edition { match *self { - SyntaxExtension::NormalTT { edition, .. } | - SyntaxExtension::ProcMacro { edition, .. } | - SyntaxExtension::AttrProcMacro(.., edition) | - SyntaxExtension::ProcMacroDerive(.., edition) => edition, + SyntaxExtension::Bang { edition, .. } | + SyntaxExtension::LegacyBang { edition, .. } | + SyntaxExtension::Attr(.., edition) | + SyntaxExtension::Derive(.., edition) => edition, // Unstable legacy stuff SyntaxExtension::NonMacroAttr { .. } | - SyntaxExtension::MultiModifier(..) | - SyntaxExtension::BuiltinDerive(..) => default_edition, + SyntaxExtension::LegacyAttr(..) | + SyntaxExtension::LegacyDerive(..) => default_edition, } } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8b49b9b028441..cdb2348f8afe4 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -389,7 +389,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item = match self.cx.resolver.resolve_macro_path( path, MacroKind::Derive, Mark::root(), Vec::new(), false) { Ok(ext) => match *ext { - BuiltinDerive(..) => item_with_markers.clone(), + SyntaxExtension::LegacyDerive(..) => item_with_markers.clone(), _ => item.clone(), }, _ => item.clone(), @@ -548,7 +548,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; - if let NonMacroAttr { mark_used: false } = *ext {} else { + if let SyntaxExtension::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); @@ -564,18 +564,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); match *ext { - NonMacroAttr { .. } => { + SyntaxExtension::NonMacroAttr { .. } => { attr::mark_known(&attr); item.visit_attrs(|attrs| attrs.push(attr)); Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item))) } - MultiModifier(ref mac) => { + SyntaxExtension::LegacyAttr(ref mac) => { let meta = attr.parse_meta(self.cx.parse_sess) .map_err(|mut e| { e.emit(); }).ok()?; let item = mac.expand(self.cx, attr.span, &meta, item); Some(invoc.fragment_kind.expect_from_annotatables(item)) } - AttrProcMacro(ref mac, ..) => { + SyntaxExtension::Attr(ref mac, ..) => { self.gate_proc_macro_attr_item(attr.span, &item); let item_tok = TokenTree::Token(DUMMY_SP, Token::Interpolated(Lrc::new(match item { Annotatable::Item(item) => token::NtItem(item), @@ -592,7 +592,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.gate_proc_macro_expansion(attr.span, &res); res } - ProcMacroDerive(..) | BuiltinDerive(..) => { + SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => { self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path)); self.cx.trace_macros_diag(); invoc.fragment_kind.dummy(attr.span) @@ -747,7 +747,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let opt_expanded = match *ext { - NormalTT { + SyntaxExtension::LegacyBang { ref expander, def_info, ref allow_internal_unstable, @@ -774,20 +774,22 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - MultiModifier(..) | AttrProcMacro(..) | SyntaxExtension::NonMacroAttr { .. } => { + SyntaxExtension::Attr(..) | + SyntaxExtension::LegacyAttr(..) | + SyntaxExtension::NonMacroAttr { .. } => { self.cx.span_err(path.span, &format!("`{}` can only be used in attributes", path)); self.cx.trace_macros_diag(); kind.dummy(span) } - ProcMacroDerive(..) | BuiltinDerive(..) => { + SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => { self.cx.span_err(path.span, &format!("`{}` is a derive macro", path)); self.cx.trace_macros_diag(); kind.dummy(span) } - SyntaxExtension::ProcMacro { ref expander, ref allow_internal_unstable, edition } => { + SyntaxExtension::Bang { ref expander, ref allow_internal_unstable, edition } => { if ident.name != kw::Invalid { let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident); @@ -885,9 +887,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; match ext { - ProcMacroDerive(expander, ..) | BuiltinDerive(expander) => { + SyntaxExtension::Derive(expander, ..) | SyntaxExtension::LegacyDerive(expander) => { let meta = match ext { - ProcMacroDerive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this + SyntaxExtension::Derive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this path: Path::from_ident(Ident::invalid()), span: DUMMY_SP, node: ast::MetaItemKind::Word, diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 8c4072db27b17..f262ab3e5fc93 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -1,7 +1,6 @@ use crate::{ast, attr}; use crate::edition::Edition; -use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; -use crate::ext::base::{NormalTT, TTMacroExpander}; +use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension, TTMacroExpander}; use crate::ext::expand::{AstFragment, AstFragmentKind}; use crate::ext::hygiene::Transparency; use crate::ext::tt::macro_parser::{Success, Error, Failure}; @@ -426,7 +425,7 @@ pub fn compile( } }); - NormalTT { + SyntaxExtension::LegacyBang { expander, def_info: Some((def.id, def.span)), transparency, diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index d6d16d0dbd155..7a8e624cb9894 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -55,7 +55,7 @@ macro_rules! derive_traits { $( resolver.add_builtin( ast::Ident::with_empty_ctxt(Symbol::intern($name)), - Lrc::new(SyntaxExtension::BuiltinDerive(Box::new($func))) + Lrc::new(SyntaxExtension::LegacyDerive(Box::new($func))) ); )* } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 7d6abd14a4a00..7c4085aa09653 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -41,7 +41,8 @@ pub mod proc_macro_impl; use rustc_data_structures::sync::Lrc; use syntax::ast; -use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension, MultiModifier}; + +use syntax::ext::base::{MacroExpanderFn, NamedSyntaxExtension, SyntaxExtension}; use syntax::ext::hygiene::Transparency; use syntax::edition::Edition; use syntax::symbol::{sym, Symbol}; @@ -57,7 +58,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( register(Symbol::intern(stringify!($name)), - NormalTT { + SyntaxExtension::LegacyBang { expander: Box::new($f as MacroExpanderFn), def_info: None, transparency: Transparency::SemiTransparent, @@ -95,13 +96,13 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, assert: assert::expand_assert, } - register(sym::test_case, MultiModifier(Box::new(test_case::expand))); - register(sym::test, MultiModifier(Box::new(test::expand_test))); - register(sym::bench, MultiModifier(Box::new(test::expand_bench))); + register(sym::test_case, SyntaxExtension::LegacyAttr(Box::new(test_case::expand))); + register(sym::test, SyntaxExtension::LegacyAttr(Box::new(test::expand_test))); + register(sym::bench, SyntaxExtension::LegacyAttr(Box::new(test::expand_bench))); // format_args uses `unstable` things internally. register(Symbol::intern("format_args"), - NormalTT { + SyntaxExtension::LegacyBang { expander: Box::new(format::expand_format_args), def_info: None, transparency: Transparency::SemiTransparent, @@ -112,7 +113,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, edition, }); register(sym::format_args_nl, - NormalTT { + SyntaxExtension::LegacyBang { expander: Box::new(format::expand_format_args_nl), def_info: None, transparency: Transparency::SemiTransparent, diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs index cf12b80848436..330459fc08f55 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs @@ -10,12 +10,10 @@ extern crate rustc_plugin; use std::borrow::ToOwned; use syntax::ast; -use syntax::ext::hygiene; use syntax::ext::build::AstBuilder; -use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT}; +use syntax::ext::base::{SyntaxExtension, TTMacroExpander, ExtCtxt, MacResult, MacEager}; use syntax::ext::hygiene::Transparency; use syntax::print::pprust; -use syntax::ptr::P; use syntax::symbol::Symbol; use syntax_pos::Span; use syntax::tokenstream::TokenStream; @@ -30,7 +28,7 @@ impl TTMacroExpander for Expander { ecx: &'cx mut ExtCtxt, sp: Span, _: TokenStream, - _: Option) -> Box { + _: Option) -> Box { let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i)) .collect::>().join(", "); MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args))) @@ -41,7 +39,7 @@ impl TTMacroExpander for Expander { pub fn plugin_registrar(reg: &mut Registry) { let args = reg.args().to_owned(); reg.register_syntax_extension(Symbol::intern("plugin_args"), - NormalTT { + SyntaxExtension::LegacyBang { expander: Box::new(Expander { args: args, }), def_info: None, transparency: Transparency::SemiTransparent, From f1867c549754403ac305be8f22a9e93642b3e288 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 7 Jun 2019 10:18:03 +0100 Subject: [PATCH 08/20] Rename `infer_types` to `infer_args` --- src/librustc/hir/lowering.rs | 4 ++-- src/librustc/hir/mod.rs | 8 ++++---- src/librustc/hir/print.rs | 16 ++++++++-------- src/librustc_typeck/astconv.rs | 30 +++++++++++++++--------------- src/librustc_typeck/check/mod.rs | 8 ++++---- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d6ad335525c14..1b433c8da60b0 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2168,7 +2168,7 @@ impl<'a> LoweringContext<'a> { itctx: ImplTraitContext<'_>, explicit_owner: Option, ) -> hir::PathSegment { - let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args { + let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { let msg = "parenthesized type parameters may only be used with a `Fn` trait"; match **generic_args { GenericArgs::AngleBracketed(ref data) => { @@ -2305,7 +2305,7 @@ impl<'a> LoweringContext<'a> { Some(id), Some(self.lower_res(res)), generic_args, - infer_types, + infer_args, ) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 2aaf5ec775d49..82b7dfd363f14 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -348,7 +348,7 @@ pub struct PathSegment { /// This only applies to expression and pattern paths, and /// out of those only the segments with no type parameters /// to begin with, e.g., `Vec::new` is `>::new::<..>`. - pub infer_types: bool, + pub infer_args: bool, } impl PathSegment { @@ -358,7 +358,7 @@ impl PathSegment { ident, hir_id: None, res: None, - infer_types: true, + infer_args: true, args: None, } } @@ -368,13 +368,13 @@ impl PathSegment { hir_id: Option, res: Option, args: GenericArgs, - infer_types: bool, + infer_args: bool, ) -> Self { PathSegment { ident, hir_id, res, - infer_types, + infer_args, args: if args.is_empty() { None } else { diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index c8615f0ed1b93..7b0a499fa5c66 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1196,7 +1196,7 @@ impl<'a> State<'a> { segment.with_generic_args(|generic_args| { if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() { - return self.print_generic_args(&generic_args, segment.infer_types, true); + return self.print_generic_args(&generic_args, segment.infer_args, true); } Ok(()) })?; @@ -1561,7 +1561,7 @@ impl<'a> State<'a> { if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident)?; segment.with_generic_args(|generic_args| { - self.print_generic_args(generic_args, segment.infer_types, + self.print_generic_args(generic_args, segment.infer_args, colons_before_params) })?; } @@ -1574,7 +1574,7 @@ impl<'a> State<'a> { if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident)?; segment.with_generic_args(|generic_args| { - self.print_generic_args(generic_args, segment.infer_types, false) + self.print_generic_args(generic_args, segment.infer_args, false) })?; } Ok(()) @@ -1602,7 +1602,7 @@ impl<'a> State<'a> { self.print_ident(segment.ident)?; segment.with_generic_args(|generic_args| { self.print_generic_args(generic_args, - segment.infer_types, + segment.infer_args, colons_before_params) })?; } @@ -1614,7 +1614,7 @@ impl<'a> State<'a> { self.print_ident(item_segment.ident)?; item_segment.with_generic_args(|generic_args| { self.print_generic_args(generic_args, - item_segment.infer_types, + item_segment.infer_args, colons_before_params) }) } @@ -1626,7 +1626,7 @@ impl<'a> State<'a> { self.print_ident(item_segment.ident)?; item_segment.with_generic_args(|generic_args| { self.print_generic_args(generic_args, - item_segment.infer_types, + item_segment.infer_args, colons_before_params) }) } @@ -1635,7 +1635,7 @@ impl<'a> State<'a> { fn print_generic_args(&mut self, generic_args: &hir::GenericArgs, - infer_types: bool, + infer_args: bool, colons_before_params: bool) -> io::Result<()> { if generic_args.parenthesized { @@ -1681,7 +1681,7 @@ impl<'a> State<'a> { // FIXME(eddyb): this would leak into error messages (e.g., // "non-exhaustive patterns: `Some::<..>(_)` not covered"). - if infer_types && false { + if infer_args && false { start_or_comma(self)?; self.s.word("..")?; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 34f817ba570e7..bac4df927b66a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -191,7 +191,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { span, def_id, generic_args, - item_segment.infer_types, + item_segment.infer_args, None, ) }); @@ -208,7 +208,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { seg: &hir::PathSegment, generics: &ty::Generics, ) -> bool { - let explicit = !seg.infer_types; + let explicit = !seg.infer_args; let impl_trait = generics.params.iter().any(|param| match param.kind { ty::GenericParamDefKind::Type { synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. @@ -259,7 +259,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { GenericArgPosition::Value }, def.parent.is_none() && def.has_self, // `has_self` - seg.infer_types || suppress_mismatch, // `infer_types` + seg.infer_args || suppress_mismatch, // `infer_args` ).0 } @@ -272,7 +272,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { args: &hir::GenericArgs, position: GenericArgPosition, has_self: bool, - infer_types: bool, + infer_args: bool, ) -> (bool, Option>) { // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. // that lifetimes will proceed types. So it suffices to check the number of each generic @@ -414,7 +414,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ); } // Note that type errors are currently be emitted *after* const errors. - if !infer_types + if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { check_kind_count( "type", @@ -511,7 +511,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } // Check whether this segment takes generic arguments and the user has provided any. - let (generic_args, infer_types) = args_for_def_id(def_id); + let (generic_args, infer_args) = args_for_def_id(def_id); let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()) .peekable(); @@ -535,7 +535,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { | (GenericArg::Const(_), GenericParamDefKind::Lifetime) => { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. - substs.push(inferred_kind(None, param, infer_types)); + substs.push(inferred_kind(None, param, infer_args)); params.next(); } (_, _) => { @@ -556,7 +556,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. - substs.push(inferred_kind(Some(&substs), param, infer_types)); + substs.push(inferred_kind(Some(&substs), param, infer_args)); args.next(); params.next(); } @@ -592,7 +592,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { span: Span, def_id: DefId, generic_args: &'a hir::GenericArgs, - infer_types: bool, + infer_args: bool, self_ty: Option>) -> (SubstsRef<'tcx>, Vec>, Option>) { @@ -617,7 +617,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { &generic_args, GenericArgPosition::Type, has_self, - infer_types, + infer_args, ); let is_object = self_ty.map_or(false, |ty| { @@ -644,7 +644,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { self_ty.is_some(), self_ty, // Provide the generic args, and whether types should be inferred. - |_| (Some(generic_args), infer_types), + |_| (Some(generic_args), infer_args), // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| { match (¶m.kind, arg) { @@ -661,11 +661,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } }, // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_types| { + |substs, param, infer_args| { match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), GenericParamDefKind::Type { has_default, .. } => { - if !infer_types && has_default { + if !infer_args && has_default { // No type parameter provided, but a default exists. // If we are converting an object type, then the @@ -693,7 +693,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { .subst_spanned(tcx, substs.unwrap(), Some(span)) ).into() } - } else if infer_types { + } else if infer_args { // No type parameters were provided, we can infer all. if !default_needs_object_self(param) { self.ty_infer_for_def(param, span).into() @@ -880,7 +880,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { self.create_substs_for_ast_path(span, trait_def_id, generic_args, - trait_segment.infer_types, + trait_segment.infer_args, Some(self_ty)) }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a111851aa3797..c66d5ff08c0b8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5419,10 +5419,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !infer_args_for_err.contains(&index) { // Check whether the user has provided generic arguments. if let Some(ref data) = segments[index].args { - return (Some(data), segments[index].infer_types); + return (Some(data), segments[index].infer_args); } } - return (None, segments[index].infer_types); + return (None, segments[index].infer_args); } (None, true) @@ -5443,13 +5443,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }, // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_types| { + |substs, param, infer_args| { match param.kind { GenericParamDefKind::Lifetime => { self.re_infer(span, Some(param)).unwrap().into() } GenericParamDefKind::Type { has_default, .. } => { - if !infer_types && has_default { + if !infer_args && has_default { // If we have a default, then we it doesn't matter that we're not // inferring the type arguments: we provide the default where any // is missing. From 5377dea7fc8dc1f05ddc4c444fddf1994293bfeb Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 6 Jun 2019 01:55:09 +0100 Subject: [PATCH 09/20] Fix issue with const arg inference --- src/librustc_typeck/astconv.rs | 24 ++++++++++++++++++------ src/librustc_typeck/check/mod.rs | 19 ++++++++++++++++++- src/librustc_typeck/collect.rs | 20 ++++++++++++++++++-- src/librustc_typeck/error_codes.rs | 4 ++-- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index bac4df927b66a..349c4e608c244 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -13,7 +13,7 @@ use crate::middle::resolve_lifetime as rl; use crate::namespace::Namespace; use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc::traits; -use rustc::ty::{self, DefIdTree, Ty, TyCtxt, ToPredicate, TypeFoldable}; +use rustc::ty::{self, DefIdTree, Ty, TyCtxt, Const, ToPredicate, TypeFoldable}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef}; use rustc::ty::wf::object_region_bounds; @@ -61,6 +61,13 @@ pub trait AstConv<'gcx, 'tcx> { span: Span) -> Ty<'tcx> { self.ty_infer(span) } + /// What const should we use when a const is omitted? + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx>; /// Projecting an associated type from a (potentially) /// higher-ranked trait reference is more complicated, because of @@ -280,7 +287,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let param_counts = def.own_counts(); let arg_counts = args.own_counts(); let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; - let infer_consts = position != GenericArgPosition::Type && arg_counts.consts == 0; let mut defaults: ty::GenericParamCount = Default::default(); for param in &def.params { @@ -333,7 +339,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { offset ); // We enforce the following: `required` <= `provided` <= `permitted`. - // For kinds without defaults (i.e., lifetimes), `required == permitted`. + // For kinds without defaults (e.g.., lifetimes), `required == permitted`. // For other kinds (i.e., types), `permitted` may be greater than `required`. if required <= provided && provided <= permitted { return (reported_late_bound_region_err.unwrap_or(false), None); @@ -404,7 +410,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ); } // FIXME(const_generics:defaults) - if !infer_consts || arg_counts.consts > param_counts.consts { + if !infer_args || arg_counts.consts > param_counts.consts { check_kind_count( "const", param_counts.consts, @@ -707,8 +713,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } GenericParamDefKind::Const => { // FIXME(const_generics:defaults) - // We've already errored above about the mismatch. - tcx.consts.err.into() + if infer_args { + // No const parameters were provided, we can infer all. + let ty = tcx.at(span).type_of(param.def_id); + self.ct_infer(ty, Some(param), span).into() + } else { + // We've already errored above about the mismatch. + tcx.consts.err.into() + } } } }, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c66d5ff08c0b8..acb0b73af886d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -100,11 +100,12 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_target::spec::abi::Abi; use rustc::infer::opaque_types::OpaqueTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc::middle::region; use rustc::mir::interpret::{ConstValue, GlobalId}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{ - self, AdtKind, CanonicalUserType, Ty, TyCtxt, GenericParamDefKind, Visibility, + self, AdtKind, CanonicalUserType, Ty, TyCtxt, Const, GenericParamDefKind, Visibility, ToPolyTraitRef, ToPredicate, RegionKind, UserType }; use rustc::ty::adjustment::{ @@ -1959,6 +1960,22 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { span: Span) -> Ty<'tcx> { if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() { return ty; + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + if let Some(param) = param { + if let UnpackedKind::Const(ct) = self.var_for_def(span, param).unpack() { + return ct; + } + unreachable!() + } else { + self.next_const_var(ty, ConstVariableOrigin { + kind: ConstVariableOriginKind::ConstInference, + span, + }) } unreachable!() } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2751cd0a37ec0..64b92687cfe17 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -26,7 +26,7 @@ use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; use rustc::ty::subst::UnpackedKind; -use rustc::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, Const}; use rustc::ty::{ReprOptions, ToPredicate}; use rustc::util::captures::Captures; use rustc::util::nodemap::FxHashMap; @@ -47,7 +47,7 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::GenericParamKind; use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety}; -use errors::Applicability; +use errors::{Applicability, DiagnosticId}; use std::iter; @@ -204,6 +204,22 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { self.tcx().types.err } + fn ct_infer( + &self, + _: Ty<'tcx>, + _: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + self.tcx().sess.struct_span_err_with_code( + span, + "the const placeholder `_` is not allowed within types on item signatures", + DiagnosticId::Error("E0121".into()), + ).span_label(span, "not allowed in type signatures") + .emit(); + + self.tcx().consts.err + } + fn projected_ty_from_poly_trait_ref( &self, span: Span, diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index b5a50f4387581..66e9a6e6b2a2e 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -1482,8 +1482,8 @@ impl <'a> Drop for MyWrapper<'a> { "##, E0121: r##" -In order to be consistent with Rust's lack of global type inference, type -placeholders are disallowed by design in item signatures. +In order to be consistent with Rust's lack of global type inference, +type and const placeholders are disallowed by design in item signatures. Examples of this error include: From a0e3e9ab9d50c74e51a81d566c941dfee6733ce5 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 6 Jun 2019 01:55:34 +0100 Subject: [PATCH 10/20] Refactor `ty_infer` and `re_infer` --- src/librustc_typeck/astconv.rs | 31 +++++++++++++-------------- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/mod.rs | 32 ++++++++++++++++------------ src/librustc_typeck/collect.rs | 13 ++++++----- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 349c4e608c244..63d9f0920cc7b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -49,19 +49,17 @@ pub trait AstConv<'gcx, 'tcx> { -> &'tcx ty::GenericPredicates<'tcx>; /// Returns the lifetime to use when a lifetime is omitted (and not elided). - fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>) + fn re_infer( + &self, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> Option>; /// Returns the type to use when a type is omitted. - fn ty_infer(&self, span: Span) -> Ty<'tcx>; + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; - /// Same as `ty_infer`, but with a known type parameter definition. - fn ty_infer_for_def(&self, - _def: &ty::GenericParamDef, - span: Span) -> Ty<'tcx> { - self.ty_infer(span) - } - /// What const should we use when a const is omitted? + /// Returns the const to use when a const is omitted. fn ct_infer( &self, ty: Ty<'tcx>, @@ -163,7 +161,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } None => { - self.re_infer(lifetime.span, def) + self.re_infer(def, lifetime.span) .unwrap_or_else(|| { // This indicates an illegal lifetime // elision. `resolve_lifetime` should have @@ -701,11 +699,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } } else if infer_args { // No type parameters were provided, we can infer all. - if !default_needs_object_self(param) { - self.ty_infer_for_def(param, span).into() + let param = if !default_needs_object_self(param) { + Some(param) } else { - self.ty_infer(span).into() - } + None + }; + self.ty_infer(param, span).into() } else { // We've already errored above about the mismatch. tcx.types.err.into() @@ -1440,7 +1439,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { if tcx.named_region(lifetime.hir_id).is_some() { self.ast_region_to_region(lifetime, None) } else { - self.re_infer(span, None).unwrap_or_else(|| { + self.re_infer(None, span).unwrap_or_else(|| { span_err!(tcx.sess, span, E0228, "the lifetime bound for this object type cannot be deduced \ from context; please supply an explicit bound"); @@ -2134,7 +2133,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // values in a ExprKind::Closure, or as // the type of local variables. Both of these cases are // handled specially and will not descend into this routine. - self.ty_infer(ast_ty.span) + self.ty_infer(None, ast_ty.span) } hir::TyKind::CVarArgs(lt) => { let va_list_did = match tcx.lang_items().va_list() { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 4427a83562e9e..b894fc8c83c10 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -598,7 +598,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a)); let supplied_return = match decl.output { hir::Return(ref output) => astconv.ast_ty_to_ty(&output), - hir::DefaultReturn(_) => astconv.ty_infer(decl.output.span()), + hir::DefaultReturn(_) => astconv.ty_infer(None, decl.output.span()), }; let result = ty::Binder::bind(self.tcx.mk_fn_sig( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index acb0b73af886d..0b558a20ed47e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1939,8 +1939,11 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { }) } - fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>) - -> Option> { + fn re_infer( + &self, + def: Option<&ty::GenericParamDef>, + span: Span, + ) -> Option> { let v = match def { Some(def) => infer::EarlyBoundRegion(span, def.name), None => infer::MiscVariable(span) @@ -1948,18 +1951,20 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Some(self.next_region_var(v)) } - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }) + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + if let Some(param) = param { + if let UnpackedKind::Type(ty) = self.var_for_def(span, param).unpack() { + return ty; + } + unreachable!() + } else { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }) + } } - fn ty_infer_for_def(&self, - ty_param_def: &ty::GenericParamDef, - span: Span) -> Ty<'tcx> { - if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() { - return ty; fn ct_infer( &self, ty: Ty<'tcx>, @@ -1977,7 +1982,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { span, }) } - unreachable!() } fn projected_ty_from_poly_trait_ref(&self, @@ -5463,7 +5467,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |substs, param, infer_args| { match param.kind { GenericParamDefKind::Lifetime => { - self.re_infer(span, Some(param)).unwrap().into() + self.re_infer(Some(param), span).unwrap().into() } GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 64b92687cfe17..8b770096cad09 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -186,18 +186,17 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { fn re_infer( &self, - _span: Span, - _def: Option<&ty::GenericParamDef>, + _: Option<&ty::GenericParamDef>, + _: Span, ) -> Option> { None } - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - struct_span_err!( - self.tcx().sess, + fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + self.tcx().sess.struct_span_err_with_code( span, - E0121, - "the type placeholder `_` is not allowed within types on item signatures" + "the type placeholder `_` is not allowed within types on item signatures", + DiagnosticId::Error("E0121".into()), ).span_label(span, "not allowed in type signatures") .emit(); From 647b4a4deb8de06cdc375187ecaf29ebeaa65f98 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 6 Jun 2019 01:55:57 +0100 Subject: [PATCH 11/20] Add test for const generics struct constructor --- .../const-generics/array-wrapper-struct-ctor.rs | 15 +++++++++++++++ .../array-wrapper-struct-ctor.stderr | 6 ++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/ui/const-generics/array-wrapper-struct-ctor.rs create mode 100644 src/test/ui/const-generics/array-wrapper-struct-ctor.stderr diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs new file mode 100644 index 0000000000000..d83846fcf88d4 --- /dev/null +++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct ArrayStruct { + data: [T; N], +} + +struct ArrayTuple([T; N]); + +fn main() { + let _ = ArrayStruct { data: [0u32; 8] }; + let _ = ArrayTuple([0u32; 8]); +} diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr new file mode 100644 index 0000000000000..bd18264c1637d --- /dev/null +++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/array-wrapper-struct-ctor.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + From 7bb0a16ad701c1cd22c0b2c05afd55f06a532062 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 6 Jun 2019 01:56:09 +0100 Subject: [PATCH 12/20] Add test for deriving Debug for const generics --- .../derive-debug-array-wrapper.rs | 9 +++++++++ .../derive-debug-array-wrapper.stderr | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/test/ui/const-generics/derive-debug-array-wrapper.rs create mode 100644 src/test/ui/const-generics/derive-debug-array-wrapper.stderr diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.rs b/src/test/ui/const-generics/derive-debug-array-wrapper.rs new file mode 100644 index 0000000000000..a29cb90ebb79a --- /dev/null +++ b/src/test/ui/const-generics/derive-debug-array-wrapper.rs @@ -0,0 +1,9 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +#[derive(Debug)] +struct X { + a: [u32; N], //~ ERROR `[u32; _]` doesn't implement `std::fmt::Debug` +} + +fn main() {} diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.stderr b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr new file mode 100644 index 0000000000000..5bab1d1b54a3e --- /dev/null +++ b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/derive-debug-array-wrapper.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0277]: `[u32; _]` doesn't implement `std::fmt::Debug` + --> $DIR/derive-debug-array-wrapper.rs:6:5 + | +LL | a: [u32; N], + | ^^^^^^^^^^^ `[u32; _]` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `[u32; _]` + = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u32; _]` + = note: required for the cast to the object type `dyn std::fmt::Debug` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From f11e6f7fa7d0a8ff1e73ff28b26667ee0a1acd87 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 7 Jun 2019 00:21:16 +0100 Subject: [PATCH 13/20] Fix issue with path segment lowering with const args --- src/librustc/hir/lowering.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 1b433c8da60b0..81ea96c0eb732 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2230,9 +2230,9 @@ impl<'a> LoweringContext<'a> { .collect(); if expected_lifetimes > 0 && param_mode == ParamMode::Explicit { let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", "); - let no_ty_args = generic_args.args.len() == expected_lifetimes; + let no_non_lt_args = generic_args.args.len() == expected_lifetimes; let no_bindings = generic_args.bindings.is_empty(); - let (incl_angl_brckt, insertion_span, suggestion) = if no_ty_args && no_bindings { + let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings { // If there are no (non-implicit) generic args or associated type // bindings, our suggestion includes the angle brackets. (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion)) @@ -2240,7 +2240,7 @@ impl<'a> LoweringContext<'a> { // Otherwise (sorry, this is kind of gross) we need to infer the // place to splice in the `'_, ` from the generics that do exist. let first_generic_span = first_generic_span - .expect("already checked that type args or bindings exist"); + .expect("already checked that non-lifetime args or bindings exist"); (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion)) }; match self.anonymous_lifetime_mode { @@ -2263,7 +2263,7 @@ impl<'a> LoweringContext<'a> { expected_lifetimes, path_span, incl_angl_brckt, - insertion_span, + insertion_sp, suggestion, ); err.emit(); @@ -2280,7 +2280,7 @@ impl<'a> LoweringContext<'a> { expected_lifetimes, path_span, incl_angl_brckt, - insertion_span, + insertion_sp, suggestion, ) ); @@ -2316,9 +2316,10 @@ impl<'a> LoweringContext<'a> { mut itctx: ImplTraitContext<'_>, ) -> (hir::GenericArgs, bool) { let &AngleBracketedArgs { ref args, ref constraints, .. } = data; - let has_types = args.iter().any(|arg| match arg { + let has_non_lt_args = args.iter().any(|arg| match arg { + ast::GenericArg::Lifetime(_) => false, ast::GenericArg::Type(_) => true, - _ => false, + ast::GenericArg::Const(_) => true, }); ( hir::GenericArgs { @@ -2328,7 +2329,7 @@ impl<'a> LoweringContext<'a> { .collect(), parenthesized: false, }, - !has_types && param_mode == ParamMode::Optional + !has_non_lt_args && param_mode == ParamMode::Optional ) } From 00f8f82a23dcd569ad203396f6e3e15c228fc444 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Jun 2019 17:34:41 +0200 Subject: [PATCH 14/20] some more comments for const_qualif --- src/librustc_mir/transform/qualify_consts.rs | 43 +++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 64aecee633719..7b2c8af5e35e2 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -135,6 +135,12 @@ enum ValueSource<'a, 'tcx> { }, } +/// A "qualif" is a way to lookg for something "bad" in the MIR that would prevent +/// proper const evaluation. So `return true` means "I found something bad, no reason +/// to go on searching". `false` is only returned if we definitely cannot find anything +/// bad anywhere. +/// +/// The default implementations proceed structurally. trait Qualif { const IDX: usize; @@ -285,7 +291,9 @@ trait Qualif { } } -// Constant containing interior mutability (UnsafeCell). +/// Constant containing interior mutability (UnsafeCell). +/// This must be ruled out to make sure that evaluating the constant at compile-time +/// and run-time would produce the same result. struct HasMutInterior; impl Qualif for HasMutInterior { @@ -343,7 +351,9 @@ impl Qualif for HasMutInterior { } } -// Constant containing an ADT that implements Drop. +/// Constant containing an ADT that implements Drop. +/// This must be ruled out because we cannot run `Drop` during compile-time +/// as that might not be a `const fn`. struct NeedsDrop; impl Qualif for NeedsDrop { @@ -366,8 +376,11 @@ impl Qualif for NeedsDrop { } } -// Not promotable at all - non-`const fn` calls, asm!, -// pointer comparisons, ptr-to-int casts, etc. +/// Not promotable at all - non-`const fn` calls, asm!, +/// pointer comparisons, ptr-to-int casts, etc. +/// Inside a const context all constness rules apply, so promotion simply has to follow the regular +/// constant rules (modulo interior mutability or `Drop` rules which are handled `HasMutInterior` +/// and `NeedsDrop` respectively). struct IsNotPromotable; impl Qualif for IsNotPromotable { @@ -511,12 +524,9 @@ impl Qualif for IsNotPromotable { /// Refers to temporaries which cannot be promoted *implicitly*. /// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`. -/// Inside a const context all constness rules -/// apply, so implicit promotion simply has to follow the regular constant rules (modulo interior -/// mutability or `Drop` rules which are handled `HasMutInterior` and `NeedsDrop` respectively). -/// Implicit promotion inside regular functions does not happen if `const fn` calls are involved, -/// as the call may be perfectly alright at runtime, but fail at compile time e.g. due to addresses -/// being compared inside the function. +/// Implicit promotion has almost the same rules, except that it does not happen if `const fn` +/// calls are involved. The call may be perfectly alright at runtime, but fail at compile time +/// e.g. due to addresses being compared inside the function. struct IsNotImplicitlyPromotable; impl Qualif for IsNotImplicitlyPromotable { @@ -589,6 +599,11 @@ impl ConstCx<'_, 'tcx> { } } +/// Checks MIR for const-correctness, using `ConstCx` +/// for value qualifications, and accumulates writes of +/// rvalue/call results to locals, in `local_qualif`. +/// For functions (constant or not), it also records +/// candidates for promotion in `promotion_candidates`. struct Checker<'a, 'tcx> { cx: ConstCx<'a, 'tcx>, @@ -757,6 +772,9 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // `let _: &'static _ = &(Cell::new(1), 2).1;` let mut local_qualifs = self.qualifs_in_local(local); local_qualifs[HasMutInterior] = false; + // Make sure there is no reason to prevent promotion. + // This is, in particular, the "implicit promotion" version of + // the check making sure that we don't run drop glue during const-eval. if !local_qualifs.0.iter().any(|&qualif| qualif) { debug!("qualify_consts: promotion candidate: {:?}", candidate); self.promotion_candidates.push(candidate); @@ -920,11 +938,6 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } } -/// Checks MIR for const-correctness, using `ConstCx` -/// for value qualifications, and accumulates writes of -/// rvalue/call results to locals, in `local_qualif`. -/// For functions (constant or not), it also records -/// candidates for promotion in `promotion_candidates`. impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { fn visit_place_base( &mut self, From 5aaf72f0f9fa8ec0119bd9d87b8a429fa86db982 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Jun 2019 17:41:16 +0200 Subject: [PATCH 15/20] replace some mode comparisons by more readable function call, rename some Mode, and more comments --- src/librustc_mir/transform/qualify_consts.rs | 118 +++++++++++-------- 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 7b2c8af5e35e2..ce6834efeb964 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -35,11 +35,26 @@ use super::promote_consts::{self, Candidate, TempState}; /// What kind of item we are in. #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum Mode { - Const, + /// A `static` item. Static, + /// A `static mut` item. StaticMut, + /// A `const fn` item. ConstFn, - Fn + /// A `const` item or an anonymous constant (e.g. in array lengths). + Const, + /// Other type of `fn`. + NonConstFn, +} + +impl Mode { + /// Determine whether we are running in "const context". "const context" refers + /// to code type-checked according to the rules of the "const type system": + /// the bodies of const/static items and `const fn`. + #[inline] + fn requires_const_checking(self) -> bool { + self != Mode::NonConstFn + } } impl fmt::Display for Mode { @@ -48,7 +63,7 @@ impl fmt::Display for Mode { Mode::Const => write!(f, "constant"), Mode::Static | Mode::StaticMut => write!(f, "static"), Mode::ConstFn => write!(f, "constant function"), - Mode::Fn => write!(f, "function") + Mode::NonConstFn => write!(f, "function") } } } @@ -135,10 +150,10 @@ enum ValueSource<'a, 'tcx> { }, } -/// A "qualif" is a way to lookg for something "bad" in the MIR that would prevent -/// proper const evaluation. So `return true` means "I found something bad, no reason -/// to go on searching". `false` is only returned if we definitely cannot find anything -/// bad anywhere. +/// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some +/// code for promotion or prevent it from evaluating at compile time. So `return true` means +/// "I found something bad, no reason to go on searching". `false` is only returned if we +/// definitely cannot find anything bad anywhere. /// /// The default implementations proceed structurally. trait Qualif { @@ -291,9 +306,11 @@ trait Qualif { } } -/// Constant containing interior mutability (UnsafeCell). +/// Constant containing interior mutability (`UnsafeCell`). /// This must be ruled out to make sure that evaluating the constant at compile-time -/// and run-time would produce the same result. +/// and run-time would produce the same result. In particular, promotion of temporaries +/// must not change program behavior; if the promoted could be written to, that would +/// be a problem. struct HasMutInterior; impl Qualif for HasMutInterior { @@ -322,10 +339,10 @@ impl Qualif for HasMutInterior { _ => return true, } } else if let ty::Array(_, len) = ty.sty { - // FIXME(eddyb) the `cx.mode == Mode::Fn` condition + // FIXME(eddyb) the `cx.mode == Mode::NonConstFn` condition // seems unnecessary, given that this is merely a ZST. match len.assert_usize(cx.tcx) { - Some(0) if cx.mode == Mode::Fn => {}, + Some(0) if cx.mode == Mode::NonConstFn => {}, _ => return true, } } else { @@ -351,9 +368,10 @@ impl Qualif for HasMutInterior { } } -/// Constant containing an ADT that implements Drop. -/// This must be ruled out because we cannot run `Drop` during compile-time -/// as that might not be a `const fn`. +/// Constant containing an ADT that implements `Drop`. +/// This must be ruled out (a) because we cannot run `Drop` during compile-time +/// as that might not be a `const fn`, and (b) because implicit promotion would +/// remove side-effects that occur as part of dropping that value. struct NeedsDrop; impl Qualif for NeedsDrop { @@ -376,11 +394,12 @@ impl Qualif for NeedsDrop { } } -/// Not promotable at all - non-`const fn` calls, asm!, +/// Not promotable at all - non-`const fn` calls, `asm!`, /// pointer comparisons, ptr-to-int casts, etc. /// Inside a const context all constness rules apply, so promotion simply has to follow the regular /// constant rules (modulo interior mutability or `Drop` rules which are handled `HasMutInterior` -/// and `NeedsDrop` respectively). +/// and `NeedsDrop` respectively). Basically this duplicates the checks that the const-checking +/// visitor enforces by emitting errors when working in const context. struct IsNotPromotable; impl Qualif for IsNotPromotable { @@ -411,9 +430,10 @@ impl Qualif for IsNotPromotable { ProjectionElem::Index(_) => {} ProjectionElem::Field(..) => { - if cx.mode == Mode::Fn { + if cx.mode == Mode::NonConstFn { let base_ty = proj.base.ty(cx.mir, cx.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { + // No promotion of union field accesses. if def.is_union() { return true; } @@ -427,7 +447,7 @@ impl Qualif for IsNotPromotable { fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool { match *rvalue { - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::Fn => { + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::NonConstFn => { let operand_ty = operand.ty(cx.mir, cx.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); @@ -441,7 +461,7 @@ impl Qualif for IsNotPromotable { } } - Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::Fn => { + Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::NonConstFn => { if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.mir, cx.tcx).sty { assert!(op == BinOp::Eq || op == BinOp::Ne || op == BinOp::Le || op == BinOp::Lt || @@ -524,9 +544,9 @@ impl Qualif for IsNotPromotable { /// Refers to temporaries which cannot be promoted *implicitly*. /// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`. -/// Implicit promotion has almost the same rules, except that it does not happen if `const fn` -/// calls are involved. The call may be perfectly alright at runtime, but fail at compile time -/// e.g. due to addresses being compared inside the function. +/// Implicit promotion has almost the same rules, except that disallows `const fn` except for +/// those marked `#[rustc_promotable]`. This is to avoid changing a legitimate run-time operation +/// into a failing compile-time operation e.g. due to addresses being compared inside the function. struct IsNotImplicitlyPromotable; impl Qualif for IsNotImplicitlyPromotable { @@ -538,7 +558,7 @@ impl Qualif for IsNotImplicitlyPromotable { args: &[Operand<'tcx>], _return_ty: Ty<'tcx>, ) -> bool { - if cx.mode == Mode::Fn { + if cx.mode == Mode::NonConstFn { if let ty::FnDef(def_id, _) = callee.ty(cx.mir, cx.tcx).sty { // Never promote runtime `const fn` calls of // functions without `#[rustc_promotable]`. @@ -602,8 +622,8 @@ impl ConstCx<'_, 'tcx> { /// Checks MIR for const-correctness, using `ConstCx` /// for value qualifications, and accumulates writes of /// rvalue/call results to locals, in `local_qualif`. -/// For functions (constant or not), it also records -/// candidates for promotion in `promotion_candidates`. +/// It also records candidates for promotion in `promotion_candidates`, +/// both in functions and const/static items. struct Checker<'a, 'tcx> { cx: ConstCx<'a, 'tcx>, @@ -687,7 +707,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // slightly pointless (even with feature-gating). fn not_const(&mut self) { unleash_miri!(self); - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let mut err = struct_span_err!( self.tcx.sess, self.span, @@ -722,7 +742,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { qualifs[HasMutInterior] = false; qualifs[IsNotPromotable] = true; - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { if let BorrowKind::Mut { .. } = kind { let mut err = struct_span_err!(self.tcx.sess, self.span, E0017, "references in {}s may only refer \ @@ -752,7 +772,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // We might have a candidate for promotion. let candidate = Candidate::Ref(location); - // We can only promote interior borrows of promotable temps. + // Start by traversing to the "base", with non-deref projections removed. let mut place = place; while let Place::Projection(ref proj) = *place { if proj.elem == ProjectionElem::Deref { @@ -761,6 +781,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { place = &proj.base; } debug!("qualify_consts: promotion candidate: place={:?}", place); + // We can only promote interior borrows of promotable temps (non-temps + // don't get promoted anyway). + // (If we bailed out of the loop due to a `Deref` above, we will definitely + // not enter the conditional here.) if let Place::Base(PlaceBase::Local(local)) = *place { if self.mir.local_kind(local) == LocalKind::Temp { debug!("qualify_consts: promotion candidate: local={:?}", local); @@ -771,10 +795,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // `HasMutInterior`, from a type that does, e.g.: // `let _: &'static _ = &(Cell::new(1), 2).1;` let mut local_qualifs = self.qualifs_in_local(local); - local_qualifs[HasMutInterior] = false; - // Make sure there is no reason to prevent promotion. + // Any qualifications, except HasMutInterior (see above), disqualify + // from promotion. // This is, in particular, the "implicit promotion" version of // the check making sure that we don't run drop glue during const-eval. + local_qualifs[HasMutInterior] = false; if !local_qualifs.0.iter().any(|&qualif| qualif) { debug!("qualify_consts: promotion candidate: {:?}", candidate); self.promotion_candidates.push(candidate); @@ -821,7 +846,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { debug!("store to {:?} {:?}", kind, index); // Only handle promotable temps in non-const functions. - if self.mode == Mode::Fn { + if self.mode == Mode::NonConstFn { if kind != LocalKind::Temp || !self.temp_promotion_state[index].is_promotable() { return; @@ -956,7 +981,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { .get_attrs(*def_id) .iter() .any(|attr| attr.check_name(sym::thread_local)) { - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { span_err!(self.tcx.sess, self.span, E0625, "thread-local statics cannot be \ accessed at compile-time"); @@ -980,7 +1005,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } unleash_miri!(self); - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let mut err = struct_span_err!(self.tcx.sess, self.span, E0013, "{}s cannot refer to statics, use \ a constant instead", self.mode); @@ -1018,7 +1043,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } let base_ty = proj.base.ty(self.mir, self.tcx).ty; match self.mode { - Mode::Fn => {}, + Mode::NonConstFn => {}, _ => { if let ty::RawPtr(_) = base_ty.sty { if !self.tcx.features().const_raw_ptr_deref { @@ -1054,7 +1079,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } }, - | Mode::Fn + | Mode::NonConstFn | Mode::Static | Mode::StaticMut | Mode::Const @@ -1144,7 +1169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { (CastTy::Ptr(_), CastTy::Int(_)) | - (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::Fn => { + (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::NonConstFn => { unleash_miri!(self); if !self.tcx.features().const_raw_ptr_to_usize_cast { // in const fn and constants require the feature gate @@ -1171,7 +1196,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { op == BinOp::Offset); unleash_miri!(self); - if self.mode != Mode::Fn && !self.tcx.features().const_compare_raw_pointers { + if self.mode.requires_const_checking() && + !self.tcx.features().const_compare_raw_pointers + { // require the feature gate inside constants and const fn // FIXME: make it unsafe to use these operations emit_feature_err( @@ -1187,7 +1214,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { Rvalue::NullaryOp(NullOp::Box, _) => { unleash_miri!(self); - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let mut err = struct_span_err!(self.tcx.sess, self.span, E0010, "allocations are not allowed in {}s", self.mode); err.span_label(self.span, format!("allocation not allowed in {}s", self.mode)); @@ -1232,8 +1259,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // special intrinsic that can be called diretly without an intrinsic // feature gate needs a language feature gate "transmute" => { - // never promote transmute calls - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { // const eval transmute calls only with the feature gate if !self.tcx.features().const_transmute { emit_feature_err( @@ -1256,7 +1282,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } _ => { // In normal functions no calls are feature-gated. - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let unleash_miri = self .tcx .sess @@ -1315,7 +1341,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } ty::FnPtr(_) => { - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let mut err = self.tcx.sess.struct_span_err( self.span, &format!("function pointers are not allowed in const fn")); @@ -1374,7 +1400,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { self.super_terminator_kind(kind, location); // Deny *any* live drops anywhere other than functions. - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { unleash_miri!(self); // HACK(eddyb): emulate a bit of dataflow analysis, // conservatively, that drop elaboration will do. @@ -1485,12 +1511,12 @@ impl MirPass for QualifyAndPromoteConstants { let id = tcx.hir().as_local_hir_id(def_id).unwrap(); let mut const_promoted_temps = None; let mode = match tcx.hir().body_owner_kind_by_hir_id(id) { - hir::BodyOwnerKind::Closure => Mode::Fn, + hir::BodyOwnerKind::Closure => Mode::NonConstFn, hir::BodyOwnerKind::Fn => { if tcx.is_const_fn(def_id) { Mode::ConstFn } else { - Mode::Fn + Mode::NonConstFn } } hir::BodyOwnerKind::Const => { @@ -1502,7 +1528,7 @@ impl MirPass for QualifyAndPromoteConstants { }; debug!("run_pass: mode={:?}", mode); - if mode == Mode::Fn || mode == Mode::ConstFn { + if mode == Mode::NonConstFn || mode == Mode::ConstFn { // This is ugly because Checker holds onto mir, // which can't be mutated until its scope ends. let (temps, candidates) = { From 7e96bd080936a318b62e3ccaccca47b1c4e664e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Jun 2019 11:47:52 +0200 Subject: [PATCH 16/20] avoid 'const-context' terminology --- src/librustc_mir/transform/qualify_consts.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ce6834efeb964..f7f3e61eaa489 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -48,9 +48,8 @@ enum Mode { } impl Mode { - /// Determine whether we are running in "const context". "const context" refers - /// to code type-checked according to the rules of the "const type system": - /// the bodies of const/static items and `const fn`. + /// Determine whether we have to do full const-checking because syntactically, we + /// are required to be "const". #[inline] fn requires_const_checking(self) -> bool { self != Mode::NonConstFn From 4dbd279df1ed4f6f9ab533cffe112d23a4fd45a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Jun 2019 12:50:05 +0200 Subject: [PATCH 17/20] const-correctness might be confusing for C++ people --- src/librustc_mir/transform/qualify_consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f7f3e61eaa489..aba4793941e61 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -618,7 +618,7 @@ impl ConstCx<'_, 'tcx> { } } -/// Checks MIR for const-correctness, using `ConstCx` +/// Checks MIR for being admissible as a compile-time constant, using `ConstCx` /// for value qualifications, and accumulates writes of /// rvalue/call results to locals, in `local_qualif`. /// It also records candidates for promotion in `promotion_candidates`, From 38c7f3eff5a0f3630cac785f3f4191ceb1c2647b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Jun 2019 12:52:01 +0200 Subject: [PATCH 18/20] comments --- src/librustc_mir/transform/qualify_consts.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index aba4793941e61..46b34295881b4 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -307,9 +307,9 @@ trait Qualif { /// Constant containing interior mutability (`UnsafeCell`). /// This must be ruled out to make sure that evaluating the constant at compile-time -/// and run-time would produce the same result. In particular, promotion of temporaries -/// must not change program behavior; if the promoted could be written to, that would -/// be a problem. +/// and at *any point* during the run-time would produce the same result. In particular, +/// promotion of temporaries must not change program behavior; if the promoted could be +/// written to, that would be a problem. struct HasMutInterior; impl Qualif for HasMutInterior { From 1d045149f024f738c9175316a3660f6358ec86bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 9 Jun 2019 21:37:26 +0200 Subject: [PATCH 19/20] submodules: update clippy from 71be6f62 to c0dbd34b Changes: ```` travis: disable rls integration test. rustup https://github.com/rust-lang/rust/pull/61669/ Add OUTER_EXPN_INFO lint ```` --- src/tools/clippy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy b/src/tools/clippy index 71be6f62fa920..c0dbd34ba99a9 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 71be6f62fa920c0bd10cdf3a29aeb8c6719a8075 +Subproject commit c0dbd34ba99a949ece25c297a4a377685eb89c7c From 35b5f4377028e34dc4df1ce67c225d2926c6c7a7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Jun 2019 12:08:38 +1000 Subject: [PATCH 20/20] Special-case literals in `parse_bottom_expr`. This makes parsing faster, particularly for code with large constants, for two reasons: - it skips all the keyword comparisons for literals; - it replaces the unnecessary `parse_literal_maybe_minus` call with `parse_lit`, avoiding an unnecessary allocation via `mk_expr`. --- src/libsyntax/parse/parser.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 43e7c9330e418..9b9954859be49 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2002,8 +2002,29 @@ impl<'a> Parser<'a> { let ex: ExprKind; + macro_rules! parse_lit { + () => { + match self.parse_lit() { + Ok(literal) => { + hi = self.prev_span; + ex = ExprKind::Lit(literal); + } + Err(mut err) => { + self.cancel(&mut err); + return Err(self.expected_expression_found()); + } + } + } + } + // Note: when adding new syntax here, don't forget to adjust TokenKind::can_begin_expr(). match self.token.kind { + // This match arm is a special-case of the `_` match arm below and + // could be removed without changing functionality, but it's faster + // to have it here, especially for programs with large constants. + token::Literal(_) => { + parse_lit!() + } token::OpenDelim(token::Paren) => { self.bump(); @@ -2249,16 +2270,7 @@ impl<'a> Parser<'a> { self.bump(); return Ok(self.mk_expr(self.span, ExprKind::Err, ThinVec::new())); } - match self.parse_literal_maybe_minus() { - Ok(expr) => { - hi = expr.span; - ex = expr.node.clone(); - } - Err(mut err) => { - self.cancel(&mut err); - return Err(self.expected_expression_found()); - } - } + parse_lit!() } } }