From 72e2cfd93438ef0109cbaca9f961efa5ac6d4f84 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 19 Aug 2019 18:26:08 -0400 Subject: Remove serialization of diagnostics to files This is no longer used by the index generator and was always an unstable compiler detail, so strip it out. This also leaves in RUSTC_ERROR_METADATA_DST since the stage0 compiler still needs it to be set. --- src/libsyntax/diagnostics/metadata.rs | 93 ----------------------------------- src/libsyntax/diagnostics/plugin.rs | 34 ++----------- src/libsyntax/lib.rs | 1 - 3 files changed, 4 insertions(+), 124 deletions(-) delete mode 100644 src/libsyntax/diagnostics/metadata.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/diagnostics/metadata.rs b/src/libsyntax/diagnostics/metadata.rs deleted file mode 100644 index 53f37bb10bd..00000000000 --- a/src/libsyntax/diagnostics/metadata.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! This module contains utilities for outputting metadata for diagnostic errors. -//! -//! Each set of errors is mapped to a metadata file by a name, which is -//! currently always a crate name. - -use std::collections::BTreeMap; -use std::env; -use std::fs::{remove_file, create_dir_all, File}; -use std::io::Write; -use std::path::PathBuf; -use std::error::Error; -use rustc_serialize::json::as_json; - -use syntax_pos::{Span, FileName}; - -use crate::ext::base::ExtCtxt; -use crate::diagnostics::plugin::{ErrorMap, ErrorInfo}; - -/// JSON encodable/decodable version of `ErrorInfo`. -#[derive(PartialEq, RustcDecodable, RustcEncodable)] -pub struct ErrorMetadata { - pub description: Option, - pub use_site: Option -} - -/// Mapping from error codes to metadata that can be (de)serialized. -pub type ErrorMetadataMap = BTreeMap; - -/// JSON encodable error location type with filename and line number. -#[derive(PartialEq, RustcDecodable, RustcEncodable)] -pub struct ErrorLocation { - pub filename: FileName, - pub line: usize -} - -impl ErrorLocation { - /// Creates an error location from a span. - pub fn from_span(ecx: &ExtCtxt<'_>, sp: Span) -> ErrorLocation { - let loc = ecx.source_map().lookup_char_pos(sp.lo()); - ErrorLocation { - filename: loc.file.name.clone(), - line: loc.line - } - } -} - -/// Gets the directory where metadata for a given `prefix` should be stored. -/// -/// See `output_metadata`. -pub fn get_metadata_dir(prefix: &str) -> PathBuf { - env::var_os("RUSTC_ERROR_METADATA_DST") - .map(PathBuf::from) - .expect("env var `RUSTC_ERROR_METADATA_DST` isn't set") - .join(prefix) -} - -/// Map `name` to a path in the given directory: /.json -fn get_metadata_path(directory: PathBuf, name: &str) -> PathBuf { - directory.join(format!("{}.json", name)) -} - -/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `prefix/name`. -/// -/// For our current purposes the prefix is the target architecture and the name is a crate name. -/// If an error occurs steps will be taken to ensure that no file is created. -pub fn output_metadata(ecx: &ExtCtxt<'_>, prefix: &str, name: &str, err_map: &ErrorMap) - -> Result<(), Box> -{ - // Create the directory to place the file in. - let metadata_dir = get_metadata_dir(prefix); - create_dir_all(&metadata_dir)?; - - // Open the metadata file. - let metadata_path = get_metadata_path(metadata_dir, name); - let mut metadata_file = File::create(&metadata_path)?; - - // Construct a serializable map. - let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| { - let key = k.as_str().to_string(); - let value = ErrorMetadata { - description: description.map(|n| n.as_str().to_string()), - use_site: use_site.map(|sp| ErrorLocation::from_span(ecx, sp)) - }; - (key, value) - }).collect::(); - - // Write the data to the file, deleting it if the write fails. - let result = write!(&mut metadata_file, "{}", as_json(&json_map)); - if result.is_err() { - remove_file(&metadata_path)?; - } - Ok(result?) -} diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 9618b5acfb0..e9a55af52e8 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::env; use crate::ast::{self, Ident, Name}; use crate::source_map; @@ -12,8 +11,6 @@ use crate::tokenstream::{TokenTree}; use smallvec::smallvec; use syntax_pos::Span; -use crate::diagnostics::metadata::output_metadata; - pub use errors::*; // Maximum width of any line in an extended error description (inclusive). @@ -127,36 +124,13 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt<'_>, token_tree: &[TokenTree]) -> Box { assert_eq!(token_tree.len(), 3); - let (crate_name, ident) = match (&token_tree[0], &token_tree[2]) { - ( - // Crate name. - &TokenTree::Token(Token { kind: token::Ident(crate_name, _), .. }), - // DIAGNOSTICS ident. - &TokenTree::Token(Token { kind: token::Ident(name, _), span }) - ) => (crate_name, Ident::new(name, span)), + let ident = match &token_tree[2] { + // DIAGNOSTICS ident. + &TokenTree::Token(Token { kind: token::Ident(name, _), span }) + => Ident::new(name, span), _ => unreachable!() }; - // Output error metadata to `tmp/extended-errors//.json` - if let Ok(target_triple) = env::var("CFG_COMPILER_HOST_TRIPLE") { - ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { - if let Err(e) = output_metadata(ecx, - &target_triple, - &crate_name.as_str(), - diagnostics) { - ecx.span_bug(span, &format!( - "error writing metadata for triple `{}` and crate `{}`, error: {}, \ - cause: {:?}", - target_triple, crate_name, e.description(), e.source() - )); - } - }); - } else { - ecx.span_err(span, &format!( - "failed to write metadata for crate `{}` because $CFG_COMPILER_HOST_TRIPLE is not set", - crate_name)); - } - // Construct the output expression. let (count, expr) = ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 8ac48d8d74a..1741932c1b8 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -124,7 +124,6 @@ pub mod diagnostics { #[macro_use] pub mod macros; pub mod plugin; - pub mod metadata; } // N.B., this module needs to be declared first so diagnostics are -- cgit 1.4.1-3-g733a5 From 777a12c3a4533e70baa46391e8c557950191a7c7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Aug 2019 17:07:42 +0200 Subject: Use dedicated type for spans in pre-expansion gating. --- src/libsyntax/feature_gate.rs | 15 +++++++++------ src/libsyntax/parse/attr.rs | 5 ++--- src/libsyntax/parse/mod.rs | 32 ++++++++++++++++++-------------- src/libsyntax/parse/parser/expr.rs | 8 ++++---- src/libsyntax/parse/parser/pat.rs | 2 +- 5 files changed, 34 insertions(+), 28 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index bbc3ae28225..df86ba790d6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -2438,16 +2438,19 @@ pub fn check_crate(krate: &ast::Crate, }; macro_rules! gate_all { + ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); }; ($spans:ident, $gate:ident, $msg:literal) => { - for span in &*sess.$spans.borrow() { gate_feature!(&ctx, $gate, *span, $msg); } + for span in &*sess.gated_spans.$spans.borrow() { + gate_feature!(&ctx, $gate, *span, $msg); + } } } - gate_all!(param_attr_spans, param_attrs, "attributes on function parameters are unstable"); - gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental"); - gate_all!(async_closure_spans, async_closure, "async closures are unstable"); - gate_all!(yield_spans, generators, "yield syntax is experimental"); - gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental"); + gate_all!(param_attrs, "attributes on function parameters are unstable"); + gate_all!(let_chains, "`let` expressions in this position are experimental"); + gate_all!(async_closure, "async closures are unstable"); + gate_all!(yields, generators, "yield syntax is experimental"); + gate_all!(or_patterns, "or-patterns syntax is experimental"); let visitor = &mut PostExpansionVisitor { context: &ctx, diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index a42da112360..c703058e795 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -21,9 +21,8 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ impl<'a> Parser<'a> { crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec> { let attrs = self.parse_outer_attributes()?; - attrs.iter().for_each(|a| - self.sess.param_attr_spans.borrow_mut().push(a.span) - ); + self.sess.gated_spans.param_attrs.borrow_mut() + .extend(attrs.iter().map(|a| a.span)); Ok(attrs) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b1f3612a839..b1af4806e2d 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -39,6 +39,22 @@ crate mod unescape_error_reporting; pub type PResult<'a, T> = Result>; +/// Collected spans during parsing for places where a certain feature was +/// used and should be feature gated accordingly in `check_crate`. +#[derive(Default)] +pub struct GatedSpans { + /// Spans collected for gating `param_attrs`, e.g. `fn foo(#[attr] x: u8) {}`. + pub param_attrs: Lock>, + /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. + pub let_chains: Lock>, + /// Spans collected for gating `async_closure`, e.g. `async || ..`. + pub async_closure: Lock>, + /// Spans collected for gating `yield e?` expressions (`generators` gate). + pub yields: Lock>, + /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. + pub or_patterns: Lock>, +} + /// Info about a parsing session. pub struct ParseSess { pub span_diagnostic: Handler, @@ -58,16 +74,8 @@ pub struct ParseSess { /// operation token that followed it, but that the parser cannot identify without further /// analysis. pub ambiguous_block_expr_parse: Lock>, - pub param_attr_spans: Lock>, - // Places where `let` exprs were used and should be feature gated according to `let_chains`. - pub let_chains_spans: Lock>, - // Places where `async || ..` exprs were used and should be feature gated. - pub async_closure_spans: Lock>, - // Places where `yield e?` exprs were used and should be feature gated. - pub yield_spans: Lock>, pub injected_crate_name: Once, - // Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated. - pub or_pattern_spans: Lock>, + pub gated_spans: GatedSpans, } impl ParseSess { @@ -93,12 +101,8 @@ impl ParseSess { buffered_lints: Lock::new(vec![]), edition: ExpnId::root().expn_data().edition, ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - param_attr_spans: Lock::new(Vec::new()), - let_chains_spans: Lock::new(Vec::new()), - async_closure_spans: Lock::new(Vec::new()), - yield_spans: Lock::new(Vec::new()), injected_crate_name: Once::new(), - or_pattern_spans: Lock::new(Vec::new()), + gated_spans: GatedSpans::default(), } } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index ccc6bd15067..5da9b75d53b 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -999,7 +999,7 @@ impl<'a> Parser<'a> { } let span = lo.to(hi); - self.sess.yield_spans.borrow_mut().push(span); + self.sess.gated_spans.yields.borrow_mut().push(span); } else if self.eat_keyword(kw::Let) { return self.parse_let_expr(attrs); } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { @@ -1111,7 +1111,7 @@ impl<'a> Parser<'a> { }; if asyncness.is_async() { // Feature gate `async ||` closures. - self.sess.async_closure_spans.borrow_mut().push(self.prev_span); + self.sess.gated_spans.async_closure.borrow_mut().push(self.prev_span); } let capture_clause = self.parse_capture_clause(); @@ -1234,7 +1234,7 @@ impl<'a> Parser<'a> { if let ExprKind::Let(..) = cond.node { // Remove the last feature gating of a `let` expression since it's stable. - let last = self.sess.let_chains_spans.borrow_mut().pop(); + let last = self.sess.gated_spans.let_chains.borrow_mut().pop(); debug_assert_eq!(cond.span, last.unwrap()); } @@ -1252,7 +1252,7 @@ impl<'a> Parser<'a> { |this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) )?; let span = lo.to(expr.span); - self.sess.let_chains_spans.borrow_mut().push(span); + self.sess.gated_spans.let_chains.borrow_mut().push(span); Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs)) } diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index fd458aec743..8cfa6abbe62 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -123,7 +123,7 @@ impl<'a> Parser<'a> { let or_pattern_span = lo.to(self.prev_span); - self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span); + self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } -- cgit 1.4.1-3-g733a5 From 7ee4f1da8c75b44501c01fb3e754c1732dad76c3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Aug 2019 18:10:43 +0200 Subject: Allow 'default async fn' to parse. --- src/libsyntax/parse/parser/item.rs | 1 + src/test/ui/specialization/issue-63716-parse-async.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/test/ui/specialization/issue-63716-parse-async.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 72819c99660..03d7e922123 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -825,6 +825,7 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(1, &[ kw::Impl, kw::Const, + kw::Async, kw::Fn, kw::Unsafe, kw::Extern, diff --git a/src/test/ui/specialization/issue-63716-parse-async.rs b/src/test/ui/specialization/issue-63716-parse-async.rs new file mode 100644 index 00000000000..c3764ffaab8 --- /dev/null +++ b/src/test/ui/specialization/issue-63716-parse-async.rs @@ -0,0 +1,14 @@ +// Ensure that `default async fn` will parse. +// See issue #63716 for details. + +// check-pass +// edition:2018 + +#![feature(specialization)] + +fn main() {} + +#[cfg(FALSE)] +impl Foo for Bar { + default async fn baz() {} +} -- cgit 1.4.1-3-g733a5 From 418eb181ca5777fb06e29a2acf37a5c641340538 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 21 Aug 2019 00:23:08 +0200 Subject: async_await was stabilized in 1.39.0, not 1.38.0. --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index bce0b07db1c..f7aaf5cd22a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -855,7 +855,7 @@ declare_features! ( // Allows `const _: TYPE = VALUE`. (accepted, underscore_const_names, "1.37.0", Some(54912), None), // Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. - (accepted, async_await, "1.38.0", Some(50547), None), + (accepted, async_await, "1.39.0", Some(50547), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features -- cgit 1.4.1-3-g733a5 From 96032aa5efd82c3cddc485332162614b9b8dd3dd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 19 Aug 2019 23:35:25 +0300 Subject: expand: Keep the correct current expansion ID for eager expansions Solve the problem of `ParentScope` entries for eager expansions not exising in the resolver map by creating them on demand. --- src/librustc_resolve/macros.rs | 4 +++- src/libsyntax/ext/expand.rs | 1 - src/test/ui/hygiene/eager-from-opaque.stderr | 3 +++ src/test/ui/macros/derive-in-eager-expansion-hang.stderr | 3 +++ 4 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 01ad67252a3..8a7a30813c1 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -142,7 +142,9 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool) -> Result>, Indeterminate> { - let parent_scope = self.invocation_parent_scopes[&invoc_id]; + let inherited_parent_scope = self.invocation_parent_scopes[&invoc_id]; + let parent_scope = *self.invocation_parent_scopes.entry(invoc.expansion_data.id) + .or_insert(inherited_parent_scope); let (path, kind, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (&attr.path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c1d52c97455..5ac234b78d0 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -318,7 +318,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { progress = true; let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); - self.cx.current_expansion.id = scope; // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { diff --git a/src/test/ui/hygiene/eager-from-opaque.stderr b/src/test/ui/hygiene/eager-from-opaque.stderr index 8db96e6ac95..f696e6caff7 100644 --- a/src/test/ui/hygiene/eager-from-opaque.stderr +++ b/src/test/ui/hygiene/eager-from-opaque.stderr @@ -3,6 +3,9 @@ error: cannot find macro `foo!` in this scope | LL | foo!() | ^^^ +... +LL | format_args!(bar!()); + | ------ in this macro invocation error: aborting due to previous error diff --git a/src/test/ui/macros/derive-in-eager-expansion-hang.stderr b/src/test/ui/macros/derive-in-eager-expansion-hang.stderr index 1ef9427666b..5ca4088e585 100644 --- a/src/test/ui/macros/derive-in-eager-expansion-hang.stderr +++ b/src/test/ui/macros/derive-in-eager-expansion-hang.stderr @@ -8,6 +8,9 @@ LL | | LL | | "" LL | | } | |_____^ +... +LL | format_args!(hang!()); + | ------- in this macro invocation help: you might be missing a string literal to format with | LL | format_args!("{}", hang!()); -- cgit 1.4.1-3-g733a5 From a83c35692fa5fc65ec9860599501f1a5a5e98214 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 19 Aug 2019 23:44:57 +0300 Subject: expand: Do not do questionable span adjustment before eagerly expanding an expression Maybe it made sense when it was introduced, but now it's doing something incorrect. --- src/libsyntax/ext/base.rs | 5 +---- src/test/ui/hygiene/eager-from-opaque.rs | 4 +++- src/test/ui/hygiene/eager-from-opaque.stderr | 11 ----------- 3 files changed, 4 insertions(+), 16 deletions(-) delete mode 100644 src/test/ui/hygiene/eager-from-opaque.stderr (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b0a4a6af983..376df4062b1 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -908,12 +908,9 @@ impl<'a> ExtCtxt<'a> { /// compilation on error, merely emits a non-fatal error and returns `None`. pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, - mut expr: P, + expr: P, err_msg: &str, ) -> Result<(Symbol, ast::StrStyle, Span), Option>> { - // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. - expr.span = expr.span.apply_mark(cx.current_expansion.id); - // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); diff --git a/src/test/ui/hygiene/eager-from-opaque.rs b/src/test/ui/hygiene/eager-from-opaque.rs index 57925d626b9..6f3215dd697 100644 --- a/src/test/ui/hygiene/eager-from-opaque.rs +++ b/src/test/ui/hygiene/eager-from-opaque.rs @@ -1,6 +1,8 @@ // Opaque macro can eagerly expand its input without breaking its resolution. // Regression test for issue #63685. +// check-pass + macro_rules! foo { () => { "foo" @@ -9,7 +11,7 @@ macro_rules! foo { macro_rules! bar { () => { - foo!() //~ ERROR cannot find macro `foo!` in this scope + foo!() }; } diff --git a/src/test/ui/hygiene/eager-from-opaque.stderr b/src/test/ui/hygiene/eager-from-opaque.stderr deleted file mode 100644 index f696e6caff7..00000000000 --- a/src/test/ui/hygiene/eager-from-opaque.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: cannot find macro `foo!` in this scope - --> $DIR/eager-from-opaque.rs:12:9 - | -LL | foo!() - | ^^^ -... -LL | format_args!(bar!()); - | ------ in this macro invocation - -error: aborting due to previous error - -- cgit 1.4.1-3-g733a5 From 93d369bc2b65e822d001a8d08f99c6bbaf105ee5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 20 Aug 2019 00:24:28 +0300 Subject: resolve/expand: Rename some things for clarity and add comments --- src/librustc_resolve/macros.rs | 36 ++++++++++++++++++++++-------------- src/libsyntax/ext/base.rs | 5 +++-- src/libsyntax/ext/expand.rs | 6 ++++-- 3 files changed, 29 insertions(+), 18 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 8a7a30813c1..719167eb057 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -140,11 +140,23 @@ impl<'a> base::Resolver for Resolver<'a> { ImportResolver { r: self }.resolve_imports() } - fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool) - -> Result>, Indeterminate> { - let inherited_parent_scope = self.invocation_parent_scopes[&invoc_id]; - let parent_scope = *self.invocation_parent_scopes.entry(invoc.expansion_data.id) - .or_insert(inherited_parent_scope); + fn resolve_macro_invocation( + &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool + ) -> Result>, Indeterminate> { + let invoc_id = invoc.expansion_data.id; + let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) { + Some(parent_scope) => *parent_scope, + None => { + // If there's no entry in the table, then we are resolving an eagerly expanded + // macro, which should inherit its parent scope from its eager expansion root - + // the macro that requested this eager expansion. + let parent_scope = *self.invocation_parent_scopes.get(&eager_expansion_root) + .expect("non-eager expansion without a parent scope"); + self.invocation_parent_scopes.insert(invoc_id, parent_scope); + parent_scope + } + }; + let (path, kind, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (&attr.path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive), @@ -163,7 +175,7 @@ impl<'a> base::Resolver for Resolver<'a> { match self.resolve_macro_path(path, Some(MacroKind::Derive), &parent_scope, true, force) { Ok((Some(ref ext), _)) if ext.is_derive_copy => { - self.add_derives(invoc.expansion_data.id, SpecialDerives::COPY); + self.add_derives(invoc_id, SpecialDerives::COPY); return Ok(None); } Err(Determinacy::Undetermined) => result = Err(Indeterminate), @@ -180,19 +192,15 @@ impl<'a> base::Resolver for Resolver<'a> { let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?; let span = invoc.span(); - invoc.expansion_data.id.set_expn_data( - ext.expn_data(parent_scope.expansion, span, fast_print_path(path)) - ); + invoc_id.set_expn_data(ext.expn_data(parent_scope.expansion, span, fast_print_path(path))); if let Res::Def(_, def_id) = res { if after_derive { self.session.span_err(span, "macro attributes must be placed before `#[derive]`"); } - self.macro_defs.insert(invoc.expansion_data.id, def_id); - let normal_module_def_id = - self.macro_def_scope(invoc.expansion_data.id).normal_ancestor_id; - self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.id, - normal_module_def_id); + self.macro_defs.insert(invoc_id, def_id); + let normal_module_def_id = self.macro_def_scope(invoc_id).normal_ancestor_id; + self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id); } Ok(Some(ext)) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 376df4062b1..075e6a80013 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -682,8 +682,9 @@ pub trait Resolver { fn resolve_imports(&mut self); - fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool) - -> Result>, Indeterminate>; + fn resolve_macro_invocation( + &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool + ) -> Result>, Indeterminate>; fn check_unused_macros(&self); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 5ac234b78d0..72f2c1375e7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -305,9 +305,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { continue }; - let scope = + let eager_expansion_root = if self.monotonic { invoc.expansion_data.id } else { orig_expansion_data.id }; - let ext = match self.cx.resolver.resolve_macro_invocation(&invoc, scope, force) { + let ext = match self.cx.resolver.resolve_macro_invocation( + &invoc, eager_expansion_root, force + ) { Ok(ext) => ext, Err(Indeterminate) => { undetermined_invocations.push(invoc); -- cgit 1.4.1-3-g733a5 From 21f2e9334567b64436f4e6525c5c98adafd16ca2 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 14 Aug 2019 17:57:28 -0700 Subject: Add terminal_width debugging flag --- src/librustc/session/config.rs | 2 ++ src/librustc/session/mod.rs | 6 ++++-- src/librustc_driver/lib.rs | 12 +++++++----- src/librustc_errors/emitter.rs | 24 +++++++++++++++++------- src/librustc_errors/lib.rs | 2 +- src/librustdoc/core.rs | 1 + src/librustdoc/test.rs | 2 +- src/libsyntax/json.rs | 2 +- src/libsyntax/parse/lexer/tests.rs | 9 ++++++++- src/libsyntax/tests.rs | 13 ++++++++----- 10 files changed, 50 insertions(+), 23 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8e3b910e0da..89481e9eafd 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1292,6 +1292,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show macro backtraces even for non-local macros"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help"), + terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], + "set the current terminal width"), continue_parse_after_error: bool = (false, parse_bool, [TRACKED], "attempt to recover from parse errors (experimental)"), dep_tasks: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 61dac678912..f01883d9634 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1055,6 +1055,7 @@ fn default_emitter( Some(source_map.clone()), short, sopts.debugging_opts.teach, + sopts.debugging_opts.terminal_width, ), Some(dst) => EmitterWriter::new( dst, @@ -1062,6 +1063,7 @@ fn default_emitter( short, false, // no teach messages when writing to a buffer false, // no colors when writing to a buffer + None, // no terminal width ), }; Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) @@ -1375,7 +1377,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(pretty, json_rendered)), @@ -1389,7 +1391,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(pretty, json_rendered)), diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b19ea513b75..3d94d51f17e 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1135,11 +1135,13 @@ pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result, source_map: Option>, teach: bool, + terminal_width: Option, ) -> EmitterWriter { let (short, color_config) = self.unzip(); - EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors()) + let color = color_config.suggests_using_colors(); + EmitterWriter::new(dst, source_map, short, teach, color, terminal_width) } } @@ -296,6 +298,7 @@ pub struct EmitterWriter { short_message: bool, teach: bool, ui_testing: bool, + terminal_width: Option, } #[derive(Debug)] @@ -306,11 +309,13 @@ pub struct FileWithAnnotatedLines { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, - source_map: Option>, - short_message: bool, - teach: bool) - -> EmitterWriter { + pub fn stderr( + color_config: ColorConfig, + source_map: Option>, + short_message: bool, + teach: bool, + terminal_width: Option, + ) -> EmitterWriter { let dst = Destination::from_stderr(color_config); EmitterWriter { dst, @@ -318,6 +323,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, } } @@ -327,6 +333,7 @@ impl EmitterWriter { short_message: bool, teach: bool, colored: bool, + terminal_width: Option, ) -> EmitterWriter { EmitterWriter { dst: Raw(dst, colored), @@ -334,6 +341,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, } } @@ -1295,7 +1303,9 @@ impl EmitterWriter { width_offset + annotated_file.multiline_depth + 1 }; - let column_width = if self.ui_testing { + let column_width = if let Some(width) = self.terminal_width { + width + } else if self.ui_testing { 140 } else { term_size::dimensions().map(|(w, _)| w - code_offset).unwrap_or(140) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4018a667bf2..6585633e00a 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -383,7 +383,7 @@ impl Handler { cm: Option>, flags: HandlerFlags) -> Handler { - let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false)); + let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false, None)); Handler::with_emitter_and_flags(emitter, flags) } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 87381f224d0..98362464771 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -193,6 +193,7 @@ pub fn new_handler(error_format: ErrorOutputType, source_map.map(|cm| cm as _), short, sessopts.debugging_opts.teach, + sessopts.debugging_opts.terminal_width, ).ui_testing(ui_testing) ) }, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 83a8d3fc109..8db0eb15929 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -427,7 +427,7 @@ pub fn make_test(s: &str, // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that libsyntax emits directly into a `Sink` instead of stderr. let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = EmitterWriter::new(box io::sink(), None, false, false, false); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, cm); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 83c9c692bd3..ada46f7bc5a 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -219,7 +219,7 @@ impl Diagnostic { } let buf = BufWriter::default(); let output = buf.clone(); - je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false) + je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false, None) .ui_testing(je.ui_testing).emit_diagnostic(db); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index a915aa42fd1..963ad2c0b8f 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -10,7 +10,14 @@ use errors::{Handler, emitter::EmitterWriter}; use syntax_pos::{BytePos, Span}; fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = EmitterWriter::new(Box::new(io::sink()), Some(sm.clone()), false, false, false); + let emitter = errors::emitter::EmitterWriter::new( + Box::new(io::sink()), + Some(sm.clone()), + false, + false, + false, + None, + ); ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm) } diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs index 4c0e1e3704d..c472212bc20 100644 --- a/src/libsyntax/tests.rs +++ b/src/libsyntax/tests.rs @@ -144,11 +144,14 @@ fn test_harness(file_text: &str, span_labels: Vec, expected_output: & println!("text: {:?}", source_map.span_to_snippet(span)); } - let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), - Some(source_map.clone()), - false, - false, - false); + let emitter = EmitterWriter::new( + Box::new(Shared { data: output.clone() }), + Some(source_map.clone()), + false, + false, + false, + None, + ); let handler = Handler::with_emitter(true, None, Box::new(emitter)); handler.span_err(msp, "foo"); -- cgit 1.4.1-3-g733a5 From cc2272fe879f662bc2623fe6d96b358ed011e382 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 21 Aug 2019 12:00:36 -0700 Subject: Formatting --- src/libsyntax/parse/lexer/tests.rs | 69 +++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 24 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index 963ad2c0b8f..6faaa01321d 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -35,10 +35,11 @@ fn t1() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - let mut string_reader = setup(&sm, - &sh, - "/* my source file */ fn main() { println!(\"zebra\"); }\n" - .to_string()); + let mut string_reader = setup( + &sm, + &sh, + "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), + ); assert_eq!(string_reader.next_token(), token::Comment); assert_eq!(string_reader.next_token(), token::Whitespace); let tok1 = string_reader.next_token(); @@ -134,8 +135,10 @@ fn character_a() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token(), - mk_lit(token::Char, "a", None)); + assert_eq!( + setup(&sm, &sh, "'a'".to_string()).next_token(), + mk_lit(token::Char, "a", None), + ); }) } @@ -144,8 +147,10 @@ fn character_space() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token(), - mk_lit(token::Char, " ", None)); + assert_eq!( + setup(&sm, &sh, "' '".to_string()).next_token(), + mk_lit(token::Char, " ", None), + ); }) } @@ -154,8 +159,10 @@ fn character_escaped() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'\\n'".to_string()).next_token(), - mk_lit(token::Char, "\\n", None)); + assert_eq!( + setup(&sm, &sh, "'\\n'".to_string()).next_token(), + mk_lit(token::Char, "\\n", None), + ); }) } @@ -164,8 +171,10 @@ fn lifetime_name() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'abc".to_string()).next_token(), - token::Lifetime(Symbol::intern("'abc"))); + assert_eq!( + setup(&sm, &sh, "'abc".to_string()).next_token(), + token::Lifetime(Symbol::intern("'abc")), + ); }) } @@ -174,8 +183,10 @@ fn raw_string() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), - mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None)); + assert_eq!( + setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), + mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), + ); }) } @@ -186,11 +197,15 @@ fn literal_suffixes() { let sh = mk_sess(sm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!(setup(&sm, &sh, format!("{}suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, Some("suffix"))); + assert_eq!( + setup(&sm, &sh, format!("{}suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, Some("suffix")), + ); // with a whitespace separator: - assert_eq!(setup(&sm, &sh, format!("{} suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, None)); + assert_eq!( + setup(&sm, &sh, format!("{} suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, None), + ); }} } @@ -204,12 +219,18 @@ fn literal_suffixes() { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); - assert_eq!(setup(&sm, &sh, "2us".to_string()).next_token(), - mk_lit(token::Integer, "2", Some("us"))); - assert_eq!(setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::StrRaw(3), "raw", Some("suffix"))); - assert_eq!(setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::ByteStrRaw(3), "raw", Some("suffix"))); + assert_eq!( + setup(&sm, &sh, "2us".to_string()).next_token(), + mk_lit(token::Integer, "2", Some("us")), + ); + assert_eq!( + setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::StrRaw(3), "raw", Some("suffix")), + ); + assert_eq!( + setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), + ); }) } -- cgit 1.4.1-3-g733a5 From aaf4dc35e33eea8b658b82a307b81e63e8b214f4 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 21 Aug 2019 14:26:52 -0700 Subject: fix rebase --- src/libsyntax/parse/lexer/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index 6faaa01321d..652ae95c853 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -10,7 +10,7 @@ use errors::{Handler, emitter::EmitterWriter}; use syntax_pos::{BytePos, Span}; fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = errors::emitter::EmitterWriter::new( + let emitter = EmitterWriter::new( Box::new(io::sink()), Some(sm.clone()), false, -- cgit 1.4.1-3-g733a5 From 0fb01d219c7b7de142ad4097dd1e5cf708e7a27f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 21 Aug 2019 21:28:22 +0300 Subject: Audit uses of `apply_mark` in built-in macros Replace them with equivalents of `Span::{def_site,call_site}` from proc macro API. The new API is much less error prone and doesn't rely on macros having default transparency. --- src/libsyntax/ext/base.rs | 30 +++++++++++++++++++++++------- src/libsyntax/ext/expand.rs | 1 - src/libsyntax/ext/proc_macro_server.rs | 11 ++--------- src/libsyntax_ext/asm.rs | 2 +- src/libsyntax_ext/assert.rs | 2 +- src/libsyntax_ext/cfg.rs | 2 +- src/libsyntax_ext/concat.rs | 2 +- src/libsyntax_ext/concat_idents.rs | 2 +- src/libsyntax_ext/deriving/clone.rs | 2 +- src/libsyntax_ext/deriving/cmp/eq.rs | 2 +- src/libsyntax_ext/deriving/debug.rs | 2 +- src/libsyntax_ext/deriving/generic/ty.rs | 2 +- src/libsyntax_ext/deriving/mod.rs | 5 ++++- src/libsyntax_ext/env.rs | 2 +- src/libsyntax_ext/format.rs | 11 +++++------ src/libsyntax_ext/global_allocator.rs | 3 +-- src/libsyntax_ext/global_asm.rs | 2 +- src/libsyntax_ext/test.rs | 6 ++---- src/libsyntax_pos/lib.rs | 8 ++++++++ 19 files changed, 56 insertions(+), 41 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 075e6a80013..004ae1cf965 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -3,7 +3,7 @@ use crate::attr::{HasAttrs, Stability, Deprecation}; use crate::source_map::SourceMap; use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; -use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency}; +use crate::ext::hygiene::{ExpnId, Transparency}; use crate::mut_visit::{self, MutVisitor}; use crate::parse::{self, parser, DirectoryOwnership}; use crate::parse::token; @@ -760,23 +760,39 @@ impl<'a> ExtCtxt<'a> { pub fn call_site(&self) -> Span { self.current_expansion.id.expn_data().call_site } - pub fn backtrace(&self) -> SyntaxContext { - SyntaxContext::root().apply_mark(self.current_expansion.id) + + /// Equivalent of `Span::def_site` from the proc macro API, + /// except that the location is taken from the span passed as an argument. + pub fn with_def_site_ctxt(&self, span: Span) -> Span { + span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Opaque) + } + + /// Equivalent of `Span::call_site` from the proc macro API, + /// except that the location is taken from the span passed as an argument. + pub fn with_call_site_ctxt(&self, span: Span) -> Span { + span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Transparent) + } + + /// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items). + /// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably), + /// or with `with_call_site_ctxt` (where necessary). + pub fn with_legacy_ctxt(&self, span: Span) -> Span { + span.with_ctxt_from_mark(self.current_expansion.id, Transparency::SemiTransparent) } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Option { - let mut ctxt = self.backtrace(); + let mut expn_id = self.current_expansion.id; let mut last_macro = None; loop { - let expn_data = ctxt.outer_expn_data(); + let expn_data = expn_id.expn_data(); // Stop going up the backtrace once include! is encountered if expn_data.is_root() || expn_data.kind.descr() == sym::include { break; } - ctxt = expn_data.call_site.ctxt(); + expn_id = expn_data.call_site.ctxt().outer_expn(); last_macro = Some(expn_data.call_site); } last_macro @@ -865,7 +881,7 @@ impl<'a> ExtCtxt<'a> { ast::Ident::from_str(st) } pub fn std_path(&self, components: &[Symbol]) -> Vec { - let def_site = DUMMY_SP.apply_mark(self.current_expansion.id); + let def_site = self.with_def_site_ctxt(DUMMY_SP); iter::once(Ident::new(kw::DollarCrate, def_site)) .chain(components.iter().map(|&s| Ident::with_dummy_span(s))) .collect() diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 72f2c1375e7..4965cb097db 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -565,7 +565,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return fragment_kind.dummy(span); } let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span, path }; - let span = span.with_ctxt(self.cx.backtrace()); let items = expander.expand(self.cx, span, &meta, item); fragment_kind.expect_from_annotatables(items) } diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 1619fa69941..b1bbd2aaac9 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -7,7 +7,6 @@ use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint} use errors::{Diagnostic, DiagnosticBuilder}; use rustc_data_structures::sync::Lrc; use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span}; -use syntax_pos::hygiene::{SyntaxContext, Transparency}; use syntax_pos::symbol::{kw, sym, Symbol}; use proc_macro::{Delimiter, Level, LineColumn, Spacing}; @@ -363,16 +362,10 @@ impl<'a> Rustc<'a> { pub fn new(cx: &'a ExtCtxt<'_>) -> Self { // No way to determine def location for a proc macro right now, so use call location. let location = cx.current_expansion.id.expn_data().call_site; - let to_span = |transparency| { - location.with_ctxt( - SyntaxContext::root() - .apply_mark_with_transparency(cx.current_expansion.id, transparency), - ) - }; Rustc { sess: cx.parse_sess, - def_site: to_span(Transparency::Opaque), - call_site: to_span(Transparency::Transparent), + def_site: cx.with_def_site_ctxt(location), + call_site: cx.with_call_site_ctxt(location), } } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 644a44f1989..28f907441d8 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -63,7 +63,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::InlineAsm(P(inline_asm)), - span: sp.with_ctxt(cx.backtrace()), + span: cx.with_legacy_ctxt(sp), attrs: ThinVec::new(), })) } diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index 6301283460a..84583d0e5ec 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -23,7 +23,7 @@ pub fn expand_assert<'cx>( } }; - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_legacy_ctxt(sp); let panic_call = Mac { path: Path::from_ident(Ident::new(sym::panic, sp)), tts: custom_message.unwrap_or_else(|| { diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index 0e52c1af908..21cee8ae1cb 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -16,7 +16,7 @@ pub fn expand_cfg( sp: Span, tts: &[tokenstream::TokenTree], ) -> Box { - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_legacy_ctxt(sp); match parse_cfg(cx, sp, tts) { Ok(cfg) => { diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index 4cd17531a45..ffa5154ca0c 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -59,6 +59,6 @@ pub fn expand_syntax_ext( } else if has_errors { return DummyResult::any(sp); } - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_legacy_ctxt(sp); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 8184fc44267..96677072d1b 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -39,7 +39,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, } } - let ident = ast::Ident::new(Symbol::intern(&res_str), sp.apply_mark(cx.current_expansion.id)); + let ident = ast::Ident::new(Symbol::intern(&res_str), cx.with_legacy_ctxt(sp)); struct ConcatIdentsResult { ident: ast::Ident } diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index d030ea4a56e..4dd0ecfebef 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -112,7 +112,7 @@ fn cs_clone_shallow(name: &str, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(&[sym::clone, Symbol::intern(helper_name)]), vec![GenericArg::Type(ty)], vec![]); diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 54027c600b4..32ab47969ad 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -53,7 +53,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt<'_>, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(&[sym::cmp, Symbol::intern(helper_name)]), vec![GenericArg::Type(ty)], vec![]); diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index 44153541048..781645a574e 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -60,7 +60,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> }; // We want to make sure we have the ctxt set so that we can use unstable methods - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); let builder = Ident::from_str_and_span("debug_trait_builder", span); let builder_expr = cx.expr_ident(span, builder.clone()); diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index 7fcf036fc81..cb1c7b21fee 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -85,7 +85,7 @@ impl<'a> Path<'a> { PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()), PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()), PathKind::Std => { - let def_site = DUMMY_SP.apply_mark(cx.current_expansion.id); + let def_site = cx.with_def_site_ctxt(DUMMY_SP); idents.insert(0, Ident::new(kw::DollarCrate, def_site)); cx.path_all(span, false, idents, params, Vec::new()) } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index da68eea0c50..60b6eba7a4b 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -48,6 +48,9 @@ impl MultiItemModifier for BuiltinDerive { meta_item: &MetaItem, item: Annotatable) -> Vec { + // FIXME: Built-in derives often forget to give spans contexts, + // so we are doing it here in a centralized way. + let span = ecx.with_def_site_ctxt(span); let mut items = Vec::new(); (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); items @@ -60,7 +63,7 @@ fn call_intrinsic(cx: &ExtCtxt<'_>, intrinsic: &str, args: Vec>) -> P { - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]); let call = cx.expr_call_global(span, path, args); diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs index 9834130fa23..6343d218de8 100644 --- a/src/libsyntax_ext/env.rs +++ b/src/libsyntax_ext/env.rs @@ -20,7 +20,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>, Some(v) => v, }; - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_legacy_ctxt(sp); let e = match env::var(&*var.as_str()) { Err(..) => { let lt = cx.lifetime(sp, Ident::with_dummy_span(kw::StaticLifetime)); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 83764205a19..47394c02b41 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -12,7 +12,7 @@ use syntax::parse::token; use syntax::ptr::P; use syntax::symbol::{Symbol, sym}; use syntax::tokenstream; -use syntax_pos::{MultiSpan, Span, DUMMY_SP}; +use syntax_pos::{MultiSpan, Span}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::borrow::Cow; @@ -666,8 +666,7 @@ impl<'a, 'b> Context<'a, 'b> { // passed to this function. for (i, e) in self.args.into_iter().enumerate() { let name = names_pos[i]; - let span = - DUMMY_SP.with_ctxt(e.span.ctxt().apply_mark(self.ecx.current_expansion.id)); + let span = self.ecx.with_def_site_ctxt(e.span); pats.push(self.ecx.pat_ident(span, name)); for ref arg_ty in self.arg_unique_types[i].iter() { locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name)); @@ -745,7 +744,7 @@ impl<'a, 'b> Context<'a, 'b> { ty: &ArgumentType, arg: ast::Ident, ) -> P { - sp = sp.apply_mark(ecx.current_expansion.id); + sp = ecx.with_def_site_ctxt(sp); let arg = ecx.expr_ident(sp, arg); let trait_ = match *ty { Placeholder(ref tyname) => { @@ -798,7 +797,7 @@ fn expand_format_args_impl<'cx>( tts: &[tokenstream::TokenTree], nl: bool, ) -> Box { - sp = sp.apply_mark(ecx.current_expansion.id); + sp = ecx.with_def_site_ctxt(sp); match parse_args(ecx, sp, tts) { Ok((efmt, args, names)) => { MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl)) @@ -842,7 +841,7 @@ pub fn expand_preparsed_format_args( let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let mut macsp = ecx.call_site(); - macsp = macsp.with_ctxt(ecx.backtrace()); + macsp = ecx.with_def_site_ctxt(macsp); let msg = "format argument must be a string literal"; let fmt_sp = efmt.span; diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index d2121abe3b4..97b8087ad15 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -3,7 +3,6 @@ use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident}; use syntax::attr::check_builtin_macro_attribute; use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{kw, sym, Symbol}; use syntax_pos::Span; @@ -29,7 +28,7 @@ pub fn expand( }; // Generate a bunch of new items using the AllocFnFactory - let span = item.span.with_ctxt(SyntaxContext::root().apply_mark(ecx.current_expansion.id)); + let span = ecx.with_legacy_ctxt(item.span); let f = AllocFnFactory { span, kind: AllocatorKind::Global, diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 73ebeaec454..a8b61593db7 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -30,7 +30,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, id: ast::DUMMY_NODE_ID, node: ast::ItemKind::GlobalAsm(P(global_asm)), vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited), - span: sp.with_ctxt(cx.backtrace()), + span: cx.with_legacy_ctxt(sp), tokens: None, })]) } diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 08582e714cc..5fd87d3a0e5 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -4,7 +4,6 @@ use syntax::ast; use syntax::attr::{self, check_builtin_macro_attribute}; use syntax::ext::base::*; -use syntax::ext::hygiene::SyntaxContext; use syntax::print::pprust; use syntax::source_map::respan; use syntax::symbol::{Symbol, sym}; @@ -29,7 +28,7 @@ pub fn expand_test_case( if !ecx.ecfg.should_test { return vec![]; } - let sp = attr_sp.with_ctxt(SyntaxContext::root().apply_mark(ecx.current_expansion.id)); + let sp = ecx.with_legacy_ctxt(attr_sp); let mut item = anno_item.expect_item(); item = item.map(|mut item| { item.vis = respan(item.vis.span, ast::VisibilityKind::Public); @@ -93,8 +92,7 @@ pub fn expand_test_or_bench( return vec![Annotatable::Item(item)]; } - let ctxt = SyntaxContext::root().apply_mark(cx.current_expansion.id); - let (sp, attr_sp) = (item.span.with_ctxt(ctxt), attr_sp.with_ctxt(ctxt)); + let (sp, attr_sp) = (cx.with_legacy_ctxt(item.span), cx.with_legacy_ctxt(attr_sp)); // Gensym "test" so we can extern crate without conflicting with any local names let test_id = cx.ident_of("test").gensym(); diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index a17cd7625fb..6fffefd0d6c 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -22,6 +22,7 @@ pub mod edition; use edition::Edition; pub mod hygiene; pub use hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind, MacroKind, DesugaringKind}; +use hygiene::Transparency; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -512,6 +513,13 @@ impl Span { span.ctxt) } + /// Produces a span with the same location as `self` and context produced by a macro with the + /// given ID and transparency, assuming that macro was defined directly and not produced by + /// some other macro (which is the case for built-in and procedural macros). + pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { + self.with_ctxt(SyntaxContext::root().apply_mark_with_transparency(expn_id, transparency)) + } + #[inline] pub fn apply_mark(self, mark: ExpnId) -> Span { let span = self.data(); -- cgit 1.4.1-3-g733a5 From cf9db76454838988620acf6ba7db7bc8654b6f57 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 23 Aug 2019 01:31:01 +0300 Subject: hygiene: Require passing transparency explicitly to `apply_mark` --- src/libsyntax/ext/expand.rs | 14 ----------- src/libsyntax/ext/tt/macro_rules.rs | 21 ++++++++++------- src/libsyntax/ext/tt/transcribe.rs | 44 ++++++++++++++++++++++++++--------- src/libsyntax/tokenstream.rs | 9 +------- src/libsyntax_pos/hygiene.rs | 46 +++++++++++++------------------------ src/libsyntax_pos/lib.rs | 6 ++--- 6 files changed, 66 insertions(+), 74 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4965cb097db..c8c0f4ce36e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1388,17 +1388,3 @@ impl<'feat> ExpansionConfig<'feat> { self.features.map_or(false, |features| features.custom_inner_attributes) } } - -// A Marker adds the given mark to the syntax context. -#[derive(Debug)] -pub struct Marker(pub ExpnId); - -impl MutVisitor for Marker { - fn visit_span(&mut self, span: &mut Span) { - *span = span.apply_mark(self.0) - } - - fn visit_mac(&mut self, mac: &mut ast::Mac) { - noop_visit_mac(mac, self) - } -} diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index b057a9ad44d..9292ce334b8 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -19,6 +19,7 @@ use crate::{ast, attr, attr::TransparencyError}; use errors::{DiagnosticBuilder, FatalError}; use log::debug; +use syntax_pos::hygiene::Transparency; use syntax_pos::Span; use rustc_data_structures::fx::FxHashMap; @@ -128,6 +129,7 @@ impl<'a> ParserAnyMacro<'a> { struct MacroRulesMacroExpander { name: ast::Ident, span: Span, + transparency: Transparency, lhses: Vec, rhses: Vec, valid: bool, @@ -143,7 +145,9 @@ impl TTMacroExpander for MacroRulesMacroExpander { if !self.valid { return DummyResult::any(sp); } - generic_extension(cx, sp, self.span, self.name, input, &self.lhses, &self.rhses) + generic_extension( + cx, sp, self.span, self.name, self.transparency, input, &self.lhses, &self.rhses + ) } } @@ -158,6 +162,7 @@ fn generic_extension<'cx>( sp: Span, def_span: Span, name: ast::Ident, + transparency: Transparency, arg: TokenStream, lhses: &[quoted::TokenTree], rhses: &[quoted::TokenTree], @@ -187,7 +192,7 @@ fn generic_extension<'cx>( let rhs_spans = rhs.iter().map(|t| t.span()).collect::>(); // rhs has holes ( `$id` and `$(...)` that need filled) - let mut tts = transcribe(cx, &named_matches, rhs); + let mut tts = transcribe(cx, &named_matches, rhs, transparency); // Replace all the tokens for the corresponding positions in the macro, to maintain // proper positions in error reporting, while maintaining the macro_backtrace. @@ -415,11 +420,7 @@ pub fn compile( // that is not lint-checked and trigger the "failed to process buffered lint here" bug. valid &= macro_check::check_meta_variables(sess, ast::CRATE_NODE_ID, def.span, &lhses, &rhses); - let expander: Box<_> = - Box::new(MacroRulesMacroExpander { name: def.ident, span: def.span, lhses, rhses, valid }); - - let (default_transparency, transparency_error) = - attr::find_transparency(&def.attrs, body.legacy); + let (transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => sess.span_diagnostic.span_err( @@ -432,6 +433,10 @@ pub fn compile( None => {} } + let expander: Box<_> = Box::new(MacroRulesMacroExpander { + name: def.ident, span: def.span, transparency, lhses, rhses, valid + }); + let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable).map(|attr| { attr.meta_item_list() @@ -473,7 +478,7 @@ pub fn compile( SyntaxExtension { kind: SyntaxExtensionKind::LegacyBang(expander), span: def.span, - default_transparency, + default_transparency: transparency, allow_internal_unstable, allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe), local_inner_macros, diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 214e721fd15..30d5df13dce 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -1,9 +1,8 @@ -use crate::ast::Ident; +use crate::ast::{Ident, Mac}; use crate::ext::base::ExtCtxt; -use crate::ext::expand::Marker; use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use crate::ext::tt::quoted; -use crate::mut_visit::noop_visit_tt; +use crate::mut_visit::{self, MutVisitor}; use crate::parse::token::{self, NtTT, Token}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; @@ -11,8 +10,31 @@ use smallvec::{smallvec, SmallVec}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use syntax_pos::hygiene::{ExpnId, Transparency}; +use syntax_pos::Span; + use std::mem; +// A Marker adds the given mark to the syntax context. +struct Marker(ExpnId, Transparency); + +impl MutVisitor for Marker { + fn visit_span(&mut self, span: &mut Span) { + *span = span.apply_mark(self.0, self.1) + } + + fn visit_mac(&mut self, mac: &mut Mac) { + mut_visit::noop_visit_mac(mac, self) + } +} + +impl Marker { + fn visit_delim_span(&mut self, dspan: &mut DelimSpan) { + self.visit_span(&mut dspan.open); + self.visit_span(&mut dspan.close); + } +} + /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). enum Frame { Delimited { forest: Lrc, idx: usize, span: DelimSpan }, @@ -68,6 +90,7 @@ pub(super) fn transcribe( cx: &ExtCtxt<'_>, interp: &FxHashMap, src: Vec, + transparency: Transparency, ) -> TokenStream { // Nothing for us to transcribe... if src.is_empty() { @@ -96,6 +119,7 @@ pub(super) fn transcribe( // again, and we are done transcribing. let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); + let mut marker = Marker(cx.current_expansion.id, transparency); loop { // Look at the last frame on the stack. @@ -207,7 +231,7 @@ pub(super) fn transcribe( } // Replace the meta-var with the matched token tree from the invocation. - quoted::TokenTree::MetaVar(mut sp, ident) => { + quoted::TokenTree::MetaVar(mut sp, mut ident) => { // Find the matched nonterminal from the macro invocation, and use it to replace // the meta-var. if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { @@ -218,7 +242,7 @@ pub(super) fn transcribe( if let NtTT(ref tt) = **nt { result.push(tt.clone().into()); } else { - sp = sp.apply_mark(cx.current_expansion.id); + marker.visit_span(&mut sp); let token = TokenTree::token(token::Interpolated(nt.clone()), sp); result.push(token.into()); } @@ -232,9 +256,8 @@ pub(super) fn transcribe( } else { // If we aren't able to match the meta-var, we push it back into the result but // with modified syntax context. (I believe this supports nested macros). - let ident = - Ident::new(ident.name, ident.span.apply_mark(cx.current_expansion.id)); - sp = sp.apply_mark(cx.current_expansion.id); + marker.visit_span(&mut sp); + marker.visit_ident(&mut ident); result.push(TokenTree::token(token::Dollar, sp).into()); result.push(TokenTree::Token(Token::from_ast_ident(ident)).into()); } @@ -246,7 +269,7 @@ pub(super) fn transcribe( // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). quoted::TokenTree::Delimited(mut span, delimited) => { - span = span.apply_mark(cx.current_expansion.id); + marker.visit_delim_span(&mut span); stack.push(Frame::Delimited { forest: delimited, idx: 0, span }); result_stack.push(mem::take(&mut result)); } @@ -254,9 +277,8 @@ pub(super) fn transcribe( // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. quoted::TokenTree::Token(token) => { - let mut marker = Marker(cx.current_expansion.id); let mut tt = TokenTree::Token(token); - noop_visit_tt(&mut tt, &mut marker); + marker.visit_tt(&mut tt); result.push(tt.into()); } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 09a1b93c7bb..0d9f3769ce9 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -19,7 +19,7 @@ use crate::parse::Directory; use crate::parse::token::{self, DelimToken, Token, TokenKind}; use crate::print::pprust; -use syntax_pos::{BytePos, ExpnId, Span, DUMMY_SP}; +use syntax_pos::{BytePos, Span, DUMMY_SP}; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; use rustc_data_structures::sync::Lrc; @@ -547,11 +547,4 @@ impl DelimSpan { pub fn entire(self) -> Span { self.open.with_hi(self.close.hi()) } - - pub fn apply_mark(self, expn_id: ExpnId) -> Self { - DelimSpan { - open: self.open.apply_mark(expn_id), - close: self.close.apply_mark(expn_id), - } - } } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index c4a0e16d931..fa84dcdb7bf 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -192,10 +192,10 @@ impl HygieneData { self.syntax_context_data[ctxt.0 as usize].parent } - fn remove_mark(&self, ctxt: &mut SyntaxContext) -> ExpnId { - let outer_expn = self.outer_expn(*ctxt); + fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) { + let outer_mark = self.outer_mark(*ctxt); *ctxt = self.parent_ctxt(*ctxt); - outer_expn + outer_mark } fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> { @@ -218,20 +218,14 @@ impl HygieneData { fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option { let mut scope = None; while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) { - scope = Some(self.remove_mark(ctxt)); + scope = Some(self.remove_mark(ctxt).0); } scope } - fn apply_mark(&mut self, ctxt: SyntaxContext, expn_id: ExpnId) -> SyntaxContext { - assert_ne!(expn_id, ExpnId::root()); - self.apply_mark_with_transparency( - ctxt, expn_id, self.expn_data(expn_id).default_transparency - ) - } - - fn apply_mark_with_transparency(&mut self, ctxt: SyntaxContext, expn_id: ExpnId, - transparency: Transparency) -> SyntaxContext { + fn apply_mark( + &mut self, ctxt: SyntaxContext, expn_id: ExpnId, transparency: Transparency + ) -> SyntaxContext { assert_ne!(expn_id, ExpnId::root()); if transparency == Transparency::Opaque { return self.apply_mark_internal(ctxt, expn_id, transparency); @@ -365,15 +359,9 @@ impl SyntaxContext { SyntaxContext(raw) } - /// Extend a syntax context with a given expansion and default transparency for that expansion. - pub fn apply_mark(self, expn_id: ExpnId) -> SyntaxContext { - HygieneData::with(|data| data.apply_mark(self, expn_id)) - } - /// Extend a syntax context with a given expansion and transparency. - pub fn apply_mark_with_transparency(self, expn_id: ExpnId, transparency: Transparency) - -> SyntaxContext { - HygieneData::with(|data| data.apply_mark_with_transparency(self, expn_id, transparency)) + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { + HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) } /// Pulls a single mark off of the syntax context. This effectively moves the @@ -393,7 +381,7 @@ impl SyntaxContext { /// invocation of f that created g1. /// Returns the mark that was removed. pub fn remove_mark(&mut self) -> ExpnId { - HygieneData::with(|data| data.remove_mark(self)) + HygieneData::with(|data| data.remove_mark(self).0) } pub fn marks(self) -> Vec<(ExpnId, Transparency)> { @@ -466,8 +454,8 @@ impl SyntaxContext { let mut scope = None; let mut glob_ctxt = data.modern(glob_span.ctxt()); while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) { - scope = Some(data.remove_mark(&mut glob_ctxt)); - if data.remove_mark(self) != scope.unwrap() { + scope = Some(data.remove_mark(&mut glob_ctxt).0); + if data.remove_mark(self).0 != scope.unwrap() { return None; } } @@ -498,9 +486,9 @@ impl SyntaxContext { marks.push(data.remove_mark(&mut glob_ctxt)); } - let scope = marks.last().cloned(); - while let Some(mark) = marks.pop() { - *self = data.apply_mark(*self, mark); + let scope = marks.last().map(|mark| mark.0); + while let Some((expn_id, transparency)) = marks.pop() { + *self = data.apply_mark(*self, expn_id, transparency); } Some(scope) }) @@ -571,9 +559,7 @@ impl Span { ) -> Span { HygieneData::with(|data| { let expn_id = data.fresh_expn(Some(expn_data)); - self.with_ctxt(data.apply_mark_with_transparency( - SyntaxContext::root(), expn_id, transparency - )) + self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency)) }) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 6fffefd0d6c..3d8bfc77a89 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -517,13 +517,13 @@ impl Span { /// given ID and transparency, assuming that macro was defined directly and not produced by /// some other macro (which is the case for built-in and procedural macros). pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { - self.with_ctxt(SyntaxContext::root().apply_mark_with_transparency(expn_id, transparency)) + self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency)) } #[inline] - pub fn apply_mark(self, mark: ExpnId) -> Span { + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { let span = self.data(); - span.with_ctxt(span.ctxt.apply_mark(mark)) + span.with_ctxt(span.ctxt.apply_mark(expn_id, transparency)) } #[inline] -- cgit 1.4.1-3-g733a5 From 6548a5fa5d1f6d1794592945837111f7264ae598 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 23 Aug 2019 01:44:18 +0300 Subject: Remove default macro transparencies All transparancies are passed explicitly now. Also remove `#[rustc_macro_transparency]` annotations from built-in macros, they are no longer used. `#[rustc_macro_transparency]` only makes sense for declarative macros now. --- src/libcore/macros.rs | 8 -------- src/librustc/ich/impls_syntax.rs | 1 - src/libsyntax/ext/base.rs | 20 -------------------- src/libsyntax/ext/tt/macro_rules.rs | 1 - src/libsyntax_pos/hygiene.rs | 6 +----- 5 files changed, 1 insertion(+), 35 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 6c88a766a2f..ffaca029a8a 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -734,7 +734,6 @@ pub(crate) mod builtin { #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] #[macro_export] - #[rustc_macro_transparency = "opaque"] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) @@ -747,7 +746,6 @@ pub(crate) mod builtin { #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] #[macro_export] - #[rustc_macro_transparency = "opaque"] macro_rules! format_args_nl { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) @@ -1235,7 +1233,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro test($item:item) { /* compiler built-in */ } /// Attribute macro applied to a function to turn it into a benchmark test. @@ -1243,7 +1240,6 @@ pub(crate) mod builtin { reason = "`bench` is a part of custom test frameworks which are unstable")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro bench($item:item) { /* compiler built-in */ } /// An implementation detail of the `#[test]` and `#[bench]` macros. @@ -1251,26 +1247,22 @@ pub(crate) mod builtin { reason = "custom test frameworks are an unstable feature")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro test_case($item:item) { /* compiler built-in */ } /// Attribute macro applied to a static to register it as a global allocator. #[stable(feature = "global_allocator", since = "1.28.0")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro global_allocator($item:item) { /* compiler built-in */ } /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] - #[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(core_intrinsics, libstd_sys_internals)] pub macro RustcDecodable($item:item) { /* compiler built-in */ } /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] - #[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(core_intrinsics)] pub macro RustcEncodable($item:item) { /* compiler built-in */ } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 7003f71c8ba..05e2c7854b4 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -402,7 +402,6 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnData { parent -> _, call_site, def_site, - default_transparency, allow_internal_unstable, allow_internal_unsafe, local_inner_macros, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 004ae1cf965..a63c4181d5e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -549,8 +549,6 @@ pub struct SyntaxExtension { pub kind: SyntaxExtensionKind, /// Span of the macro definition. pub span: Span, - /// Hygienic properties of spans produced by this macro by default. - pub default_transparency: Transparency, /// Whitelist of unstable features that are treated as stable inside this macro. pub allow_internal_unstable: Option>, /// Suppresses the `unsafe_code` lint for code produced by this macro. @@ -572,22 +570,6 @@ pub struct SyntaxExtension { pub is_derive_copy: bool, } -impl SyntaxExtensionKind { - /// When a syntax extension is constructed, - /// its transparency can often be inferred from its kind. - fn default_transparency(&self) -> Transparency { - match self { - SyntaxExtensionKind::Bang(..) | - SyntaxExtensionKind::Attr(..) | - SyntaxExtensionKind::Derive(..) | - SyntaxExtensionKind::NonMacroAttr { .. } => Transparency::Opaque, - SyntaxExtensionKind::LegacyBang(..) | - SyntaxExtensionKind::LegacyAttr(..) | - SyntaxExtensionKind::LegacyDerive(..) => Transparency::SemiTransparent, - } - } -} - impl SyntaxExtension { /// Returns which kind of macro calls this syntax extension. pub fn macro_kind(&self) -> MacroKind { @@ -606,7 +588,6 @@ impl SyntaxExtension { pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension { SyntaxExtension { span: DUMMY_SP, - default_transparency: kind.default_transparency(), allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, @@ -646,7 +627,6 @@ impl SyntaxExtension { parent, call_site, def_site: self.span, - default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), allow_internal_unsafe: self.allow_internal_unsafe, local_inner_macros: self.local_inner_macros, diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 9292ce334b8..37cb8467ff5 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -478,7 +478,6 @@ pub fn compile( SyntaxExtension { kind: SyntaxExtensionKind::LegacyBang(expander), span: def.span, - default_transparency: transparency, allow_internal_unstable, allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe), local_inner_macros, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index fa84dcdb7bf..733f6f04490 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -550,8 +550,7 @@ impl Span { /// The returned span belongs to the created expansion and has the new properties, /// but its location is inherited from the current span. pub fn fresh_expansion(self, expn_data: ExpnData) -> Span { - let transparency = expn_data.default_transparency; - self.fresh_expansion_with_transparency(expn_data, transparency) + self.fresh_expansion_with_transparency(expn_data, Transparency::SemiTransparent) } pub fn fresh_expansion_with_transparency( @@ -591,8 +590,6 @@ pub struct ExpnData { /// The span of the macro definition (possibly dummy). /// This span serves only informational purpose and is not used for resolution. pub def_site: Span, - /// Transparency used by `apply_mark` for the expansion with this expansion data by default. - pub default_transparency: Transparency, /// List of #[unstable]/feature-gated features that the macro is allowed to use /// internally without forcing the whole crate to opt-in /// to them. @@ -615,7 +612,6 @@ impl ExpnData { parent: ExpnId::root(), call_site, def_site: DUMMY_SP, - default_transparency: Transparency::SemiTransparent, allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, -- cgit 1.4.1-3-g733a5 From b873743c024d018b00e1e8c863a01d2c48bcdb1b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Aug 2019 18:40:53 +0200 Subject: syntax: extract `accepted.rs` feature gates. --- src/libsyntax/feature_gate.rs | 234 +------------------------------- src/libsyntax/feature_gate/accepted.rs | 236 +++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+), 231 deletions(-) create mode 100644 src/libsyntax/feature_gate/accepted.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fad4f3da3de..32fef2fc8dd 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -12,6 +12,9 @@ //! gate usage is added, *do not remove it again* even once the feature //! becomes stable. +mod accepted; +use accepted::ACCEPTED_FEATURES; + use AttributeType::*; use AttributeGate::*; @@ -94,13 +97,6 @@ macro_rules! declare_features { $((sym::$feature, $ver, $issue, None)),+ ]; }; - - ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { - /// Those language feature has since been Accepted (it was once Active) - const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ - ]; - } } // If you change this, please modify `src/doc/unstable-book` as well. @@ -638,230 +634,6 @@ declare_features! ( (stable_removed, no_stack_check, "1.0.0", None, None), ); -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: for testing purposes - // ------------------------------------------------------------------------- - - // A temporary feature gate used to enable parser extensions needed - // to bootstrap fix for #5723. - (accepted, issue_5723_bootstrap, "1.0.0", None, None), - // These are used to test this portion of the compiler, - // they don't actually mean anything. - (accepted, test_accepted_feature, "1.0.0", None, None), - - // ------------------------------------------------------------------------- - // feature-group-end: for testing purposes - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: accepted features - // ------------------------------------------------------------------------- - - // Allows using associated `type`s in `trait`s. - (accepted, associated_types, "1.0.0", None, None), - // Allows using assigning a default type to type parameters in algebraic data type definitions. - (accepted, default_type_params, "1.0.0", None, None), - // FIXME: explain `globs`. - (accepted, globs, "1.0.0", None, None), - // Allows `macro_rules!` items. - (accepted, macro_rules, "1.0.0", None, None), - // Allows use of `&foo[a..b]` as a slicing syntax. - (accepted, slicing_syntax, "1.0.0", None, None), - // Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). - (accepted, struct_variant, "1.0.0", None, None), - // Allows indexing tuples. - (accepted, tuple_indexing, "1.0.0", None, None), - // Allows the use of `if let` expressions. - (accepted, if_let, "1.0.0", None, None), - // Allows the use of `while let` expressions. - (accepted, while_let, "1.0.0", None, None), - // Allows using `#![no_std]`. - (accepted, no_std, "1.6.0", None, None), - // Allows overloading augmented assignment operations like `a += b`. - (accepted, augmented_assignments, "1.8.0", Some(28235), None), - // Allows empty structs and enum variants with braces. - (accepted, braced_empty_structs, "1.8.0", Some(29720), None), - // Allows `#[deprecated]` attribute. - (accepted, deprecated, "1.9.0", Some(29935), None), - // Allows macros to appear in the type position. - (accepted, type_macros, "1.13.0", Some(27245), None), - // Allows use of the postfix `?` operator in expressions. - (accepted, question_mark, "1.13.0", Some(31436), None), - // Allows `..` in tuple (struct) patterns. - (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), - // Allows some increased flexibility in the name resolution rules, - // especially around globs and shadowing (RFC 1560). - (accepted, item_like_imports, "1.15.0", Some(35120), None), - // Allows using `Self` and associated types in struct expressions and patterns. - (accepted, more_struct_aliases, "1.16.0", Some(37544), None), - // Allows elision of `'static` lifetimes in `static`s and `const`s. - (accepted, static_in_const, "1.17.0", Some(35897), None), - // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. - (accepted, field_init_shorthand, "1.17.0", Some(37340), None), - // Allows the definition recursive static items. - (accepted, static_recursion, "1.17.0", Some(29719), None), - // Allows `pub(restricted)` visibilities (RFC 1422). - (accepted, pub_restricted, "1.18.0", Some(32409), None), - // Allows `#![windows_subsystem]`. - (accepted, windows_subsystem, "1.18.0", Some(37499), None), - // Allows `break {expr}` with a value inside `loop`s. - (accepted, loop_break_value, "1.19.0", Some(37339), None), - // Allows numeric fields in struct expressions and patterns. - (accepted, relaxed_adts, "1.19.0", Some(35626), None), - // Allows coercing non capturing closures to function pointers. - (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), - // Allows attributes on struct literal fields. - (accepted, struct_field_attributes, "1.20.0", Some(38814), None), - // Allows the definition of associated constants in `trait` or `impl` blocks. - (accepted, associated_consts, "1.20.0", Some(29646), None), - // Allows usage of the `compile_error!` macro. - (accepted, compile_error, "1.20.0", Some(40872), None), - // Allows code like `let x: &'static u32 = &42` to work (RFC 1414). - (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), - // Allows `Drop` types in constants (RFC 1440). - (accepted, drop_types_in_const, "1.22.0", Some(33156), None), - // Allows the sysV64 ABI to be specified on all platforms - // instead of just the platforms on which it is the C ABI. - (accepted, abi_sysv64, "1.24.0", Some(36167), None), - // Allows `repr(align(16))` struct attribute (RFC 1358). - (accepted, repr_align, "1.25.0", Some(33626), None), - // Allows '|' at beginning of match arms (RFC 1925). - (accepted, match_beginning_vert, "1.25.0", Some(44101), None), - // Allows nested groups in `use` items (RFC 2128). - (accepted, use_nested_groups, "1.25.0", Some(44494), None), - // Allows indexing into constant arrays. - (accepted, const_indexing, "1.26.0", Some(29947), None), - // Allows using `a..=b` and `..=b` as inclusive range syntaxes. - (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), - // Allows `..=` in patterns (RFC 1192). - (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), - // Allows `fn main()` with return types which implements `Termination` (RFC 1937). - (accepted, termination_trait, "1.26.0", Some(43301), None), - // Allows implementing `Clone` for closures where possible (RFC 2132). - (accepted, clone_closures, "1.26.0", Some(44490), None), - // Allows implementing `Copy` for closures where possible (RFC 2132). - (accepted, copy_closures, "1.26.0", Some(44490), None), - // Allows `impl Trait` in function arguments. - (accepted, universal_impl_trait, "1.26.0", Some(34511), None), - // Allows `impl Trait` in function return types. - (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), - // Allows using the `u128` and `i128` types. - (accepted, i128_type, "1.26.0", Some(35118), None), - // Allows default match binding modes (RFC 2005). - (accepted, match_default_bindings, "1.26.0", Some(42640), None), - // Allows `'_` placeholder lifetimes. - (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), - // Allows attributes on lifetime/type formal parameters in generics (RFC 1327). - (accepted, generic_param_attrs, "1.27.0", Some(48848), None), - // Allows `cfg(target_feature = "...")`. - (accepted, cfg_target_feature, "1.27.0", Some(29717), None), - // Allows `#[target_feature(...)]`. - (accepted, target_feature, "1.27.0", None, None), - // Allows using `dyn Trait` as a syntax for trait objects. - (accepted, dyn_trait, "1.27.0", Some(44662), None), - // Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). - (accepted, fn_must_use, "1.27.0", Some(43302), None), - // Allows use of the `:lifetime` macro fragment specifier. - (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), - // Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). - (accepted, termination_trait_test, "1.27.0", Some(48854), None), - // Allows the `#[global_allocator]` attribute. - (accepted, global_allocator, "1.28.0", Some(27389), None), - // Allows `#[repr(transparent)]` attribute on newtype structs. - (accepted, repr_transparent, "1.28.0", Some(43036), None), - // Allows procedural macros in `proc-macro` crates. - (accepted, proc_macro, "1.29.0", Some(38356), None), - // Allows `foo.rs` as an alternative to `foo/mod.rs`. - (accepted, non_modrs_mods, "1.30.0", Some(44660), None), - // Allows use of the `:vis` macro fragment specifier - (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), - // Allows importing and reexporting macros with `use`, - // enables macro modularization in general. - (accepted, use_extern_macros, "1.30.0", Some(35896), None), - // Allows keywords to be escaped for use as identifiers. - (accepted, raw_identifiers, "1.30.0", Some(48589), None), - // Allows attributes scoped to tools. - (accepted, tool_attributes, "1.30.0", Some(44690), None), - // Allows multi-segment paths in attributes and derives. - (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), - // Allows all literals in attribute lists and values of key-value pairs. - (accepted, attr_literals, "1.30.0", Some(34981), None), - // Allows inferring outlives requirements (RFC 2093). - (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), - // Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. - // This defines the behavior of panics. - (accepted, panic_handler, "1.30.0", Some(44489), None), - // Allows `#[used]` to preserve symbols (see llvm.used). - (accepted, used, "1.30.0", Some(40289), None), - // Allows `crate` in paths. - (accepted, crate_in_paths, "1.30.0", Some(45477), None), - // Allows resolving absolute paths as paths from other crates. - (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), - // Allows access to crate names passed via `--extern` through prelude. - (accepted, extern_prelude, "1.30.0", Some(44660), None), - // Allows parentheses in patterns. - (accepted, pattern_parentheses, "1.31.0", Some(51087), None), - // Allows the definition of `const fn` functions. - (accepted, min_const_fn, "1.31.0", Some(53555), None), - // Allows scoped lints. - (accepted, tool_lints, "1.31.0", Some(44690), None), - // Allows lifetime elision in `impl` headers. For example: - // + `impl Iterator for &mut Iterator` - // + `impl Debug for Foo<'_>` - (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), - // Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. - (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), - // Allows use of the `:literal` macro fragment specifier (RFC 1576). - (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), - // Allows use of `?` as the Kleene "at most one" operator in macros. - (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), - // Allows `Self` struct constructor (RFC 2302). - (accepted, self_struct_ctor, "1.32.0", Some(51994), None), - // Allows `Self` in type definitions (RFC 2300). - (accepted, self_in_typedefs, "1.32.0", Some(49303), None), - // Allows `use x::y;` to search `x` in the current scope. - (accepted, uniform_paths, "1.32.0", Some(53130), None), - // Allows integer match exhaustiveness checking (RFC 2591). - (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), - // Allows `use path as _;` and `extern crate c as _;`. - (accepted, underscore_imports, "1.33.0", Some(48216), None), - // Allows `#[repr(packed(N))]` attribute on structs. - (accepted, repr_packed, "1.33.0", Some(33158), None), - // Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). - (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), - // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. - (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), - // Allows let bindings, assignments and destructuring in `const` functions and constants. - // As long as control flow is not implemented in const eval, `&&` and `||` may not be used - // at the same time as let bindings. - (accepted, const_let, "1.33.0", Some(48821), None), - // Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. - (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), - // Allows top level or-patterns (`p | q`) in `if let` and `while let`. - (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), - // Allows `cfg(target_vendor = "...")`. - (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), - // Allows `extern crate self as foo;`. - // This puts local crate root into extern prelude under name `foo`. - (accepted, extern_crate_self, "1.34.0", Some(56409), None), - // Allows arbitrary delimited token streams in non-macro attributes. - (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), - // Allows paths to enum variants on type aliases including `Self`. - (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), - // Allows using `#[repr(align(X))]` on enums with equivalent semantics - // to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. - (accepted, repr_align_enum, "1.37.0", Some(57996), None), - // Allows `const _: TYPE = VALUE`. - (accepted, underscore_const_names, "1.37.0", Some(54912), None), - // Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. - (accepted, async_await, "1.39.0", Some(50547), None), - - // ------------------------------------------------------------------------- - // feature-group-end: accepted features - // ------------------------------------------------------------------------- -); - // If you change this, please modify `src/doc/unstable-book` as well. You must // move that documentation into the relevant place in the other docs, and // remove the chapter on the flag. diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs new file mode 100644 index 00000000000..32a0b76d5f0 --- /dev/null +++ b/src/libsyntax/feature_gate/accepted.rs @@ -0,0 +1,236 @@ +//! List of the accepted feature gates. + +use crate::symbol::{Symbol, sym}; + +macro_rules! declare_features { + ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { + /// Those language feature has since been Accepted (it was once Active) + pub const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, None)),+ + ]; + } +} + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: for testing purposes + // ------------------------------------------------------------------------- + + // A temporary feature gate used to enable parser extensions needed + // to bootstrap fix for #5723. + (accepted, issue_5723_bootstrap, "1.0.0", None, None), + // These are used to test this portion of the compiler, + // they don't actually mean anything. + (accepted, test_accepted_feature, "1.0.0", None, None), + + // ------------------------------------------------------------------------- + // feature-group-end: for testing purposes + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: accepted features + // ------------------------------------------------------------------------- + + // Allows using associated `type`s in `trait`s. + (accepted, associated_types, "1.0.0", None, None), + // Allows using assigning a default type to type parameters in algebraic data type definitions. + (accepted, default_type_params, "1.0.0", None, None), + // FIXME: explain `globs`. + (accepted, globs, "1.0.0", None, None), + // Allows `macro_rules!` items. + (accepted, macro_rules, "1.0.0", None, None), + // Allows use of `&foo[a..b]` as a slicing syntax. + (accepted, slicing_syntax, "1.0.0", None, None), + // Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). + (accepted, struct_variant, "1.0.0", None, None), + // Allows indexing tuples. + (accepted, tuple_indexing, "1.0.0", None, None), + // Allows the use of `if let` expressions. + (accepted, if_let, "1.0.0", None, None), + // Allows the use of `while let` expressions. + (accepted, while_let, "1.0.0", None, None), + // Allows using `#![no_std]`. + (accepted, no_std, "1.6.0", None, None), + // Allows overloading augmented assignment operations like `a += b`. + (accepted, augmented_assignments, "1.8.0", Some(28235), None), + // Allows empty structs and enum variants with braces. + (accepted, braced_empty_structs, "1.8.0", Some(29720), None), + // Allows `#[deprecated]` attribute. + (accepted, deprecated, "1.9.0", Some(29935), None), + // Allows macros to appear in the type position. + (accepted, type_macros, "1.13.0", Some(27245), None), + // Allows use of the postfix `?` operator in expressions. + (accepted, question_mark, "1.13.0", Some(31436), None), + // Allows `..` in tuple (struct) patterns. + (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), + // Allows some increased flexibility in the name resolution rules, + // especially around globs and shadowing (RFC 1560). + (accepted, item_like_imports, "1.15.0", Some(35120), None), + // Allows using `Self` and associated types in struct expressions and patterns. + (accepted, more_struct_aliases, "1.16.0", Some(37544), None), + // Allows elision of `'static` lifetimes in `static`s and `const`s. + (accepted, static_in_const, "1.17.0", Some(35897), None), + // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. + (accepted, field_init_shorthand, "1.17.0", Some(37340), None), + // Allows the definition recursive static items. + (accepted, static_recursion, "1.17.0", Some(29719), None), + // Allows `pub(restricted)` visibilities (RFC 1422). + (accepted, pub_restricted, "1.18.0", Some(32409), None), + // Allows `#![windows_subsystem]`. + (accepted, windows_subsystem, "1.18.0", Some(37499), None), + // Allows `break {expr}` with a value inside `loop`s. + (accepted, loop_break_value, "1.19.0", Some(37339), None), + // Allows numeric fields in struct expressions and patterns. + (accepted, relaxed_adts, "1.19.0", Some(35626), None), + // Allows coercing non capturing closures to function pointers. + (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), + // Allows attributes on struct literal fields. + (accepted, struct_field_attributes, "1.20.0", Some(38814), None), + // Allows the definition of associated constants in `trait` or `impl` blocks. + (accepted, associated_consts, "1.20.0", Some(29646), None), + // Allows usage of the `compile_error!` macro. + (accepted, compile_error, "1.20.0", Some(40872), None), + // Allows code like `let x: &'static u32 = &42` to work (RFC 1414). + (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), + // Allows `Drop` types in constants (RFC 1440). + (accepted, drop_types_in_const, "1.22.0", Some(33156), None), + // Allows the sysV64 ABI to be specified on all platforms + // instead of just the platforms on which it is the C ABI. + (accepted, abi_sysv64, "1.24.0", Some(36167), None), + // Allows `repr(align(16))` struct attribute (RFC 1358). + (accepted, repr_align, "1.25.0", Some(33626), None), + // Allows '|' at beginning of match arms (RFC 1925). + (accepted, match_beginning_vert, "1.25.0", Some(44101), None), + // Allows nested groups in `use` items (RFC 2128). + (accepted, use_nested_groups, "1.25.0", Some(44494), None), + // Allows indexing into constant arrays. + (accepted, const_indexing, "1.26.0", Some(29947), None), + // Allows using `a..=b` and `..=b` as inclusive range syntaxes. + (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), + // Allows `..=` in patterns (RFC 1192). + (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), + // Allows `fn main()` with return types which implements `Termination` (RFC 1937). + (accepted, termination_trait, "1.26.0", Some(43301), None), + // Allows implementing `Clone` for closures where possible (RFC 2132). + (accepted, clone_closures, "1.26.0", Some(44490), None), + // Allows implementing `Copy` for closures where possible (RFC 2132). + (accepted, copy_closures, "1.26.0", Some(44490), None), + // Allows `impl Trait` in function arguments. + (accepted, universal_impl_trait, "1.26.0", Some(34511), None), + // Allows `impl Trait` in function return types. + (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), + // Allows using the `u128` and `i128` types. + (accepted, i128_type, "1.26.0", Some(35118), None), + // Allows default match binding modes (RFC 2005). + (accepted, match_default_bindings, "1.26.0", Some(42640), None), + // Allows `'_` placeholder lifetimes. + (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), + // Allows attributes on lifetime/type formal parameters in generics (RFC 1327). + (accepted, generic_param_attrs, "1.27.0", Some(48848), None), + // Allows `cfg(target_feature = "...")`. + (accepted, cfg_target_feature, "1.27.0", Some(29717), None), + // Allows `#[target_feature(...)]`. + (accepted, target_feature, "1.27.0", None, None), + // Allows using `dyn Trait` as a syntax for trait objects. + (accepted, dyn_trait, "1.27.0", Some(44662), None), + // Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). + (accepted, fn_must_use, "1.27.0", Some(43302), None), + // Allows use of the `:lifetime` macro fragment specifier. + (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), + // Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). + (accepted, termination_trait_test, "1.27.0", Some(48854), None), + // Allows the `#[global_allocator]` attribute. + (accepted, global_allocator, "1.28.0", Some(27389), None), + // Allows `#[repr(transparent)]` attribute on newtype structs. + (accepted, repr_transparent, "1.28.0", Some(43036), None), + // Allows procedural macros in `proc-macro` crates. + (accepted, proc_macro, "1.29.0", Some(38356), None), + // Allows `foo.rs` as an alternative to `foo/mod.rs`. + (accepted, non_modrs_mods, "1.30.0", Some(44660), None), + // Allows use of the `:vis` macro fragment specifier + (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), + // Allows importing and reexporting macros with `use`, + // enables macro modularization in general. + (accepted, use_extern_macros, "1.30.0", Some(35896), None), + // Allows keywords to be escaped for use as identifiers. + (accepted, raw_identifiers, "1.30.0", Some(48589), None), + // Allows attributes scoped to tools. + (accepted, tool_attributes, "1.30.0", Some(44690), None), + // Allows multi-segment paths in attributes and derives. + (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), + // Allows all literals in attribute lists and values of key-value pairs. + (accepted, attr_literals, "1.30.0", Some(34981), None), + // Allows inferring outlives requirements (RFC 2093). + (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), + // Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. + // This defines the behavior of panics. + (accepted, panic_handler, "1.30.0", Some(44489), None), + // Allows `#[used]` to preserve symbols (see llvm.used). + (accepted, used, "1.30.0", Some(40289), None), + // Allows `crate` in paths. + (accepted, crate_in_paths, "1.30.0", Some(45477), None), + // Allows resolving absolute paths as paths from other crates. + (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), + // Allows access to crate names passed via `--extern` through prelude. + (accepted, extern_prelude, "1.30.0", Some(44660), None), + // Allows parentheses in patterns. + (accepted, pattern_parentheses, "1.31.0", Some(51087), None), + // Allows the definition of `const fn` functions. + (accepted, min_const_fn, "1.31.0", Some(53555), None), + // Allows scoped lints. + (accepted, tool_lints, "1.31.0", Some(44690), None), + // Allows lifetime elision in `impl` headers. For example: + // + `impl Iterator for &mut Iterator` + // + `impl Debug for Foo<'_>` + (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), + // Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. + (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), + // Allows use of the `:literal` macro fragment specifier (RFC 1576). + (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), + // Allows use of `?` as the Kleene "at most one" operator in macros. + (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), + // Allows `Self` struct constructor (RFC 2302). + (accepted, self_struct_ctor, "1.32.0", Some(51994), None), + // Allows `Self` in type definitions (RFC 2300). + (accepted, self_in_typedefs, "1.32.0", Some(49303), None), + // Allows `use x::y;` to search `x` in the current scope. + (accepted, uniform_paths, "1.32.0", Some(53130), None), + // Allows integer match exhaustiveness checking (RFC 2591). + (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), + // Allows `use path as _;` and `extern crate c as _;`. + (accepted, underscore_imports, "1.33.0", Some(48216), None), + // Allows `#[repr(packed(N))]` attribute on structs. + (accepted, repr_packed, "1.33.0", Some(33158), None), + // Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). + (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), + // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. + (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), + // Allows let bindings, assignments and destructuring in `const` functions and constants. + // As long as control flow is not implemented in const eval, `&&` and `||` may not be used + // at the same time as let bindings. + (accepted, const_let, "1.33.0", Some(48821), None), + // Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. + (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), + // Allows top level or-patterns (`p | q`) in `if let` and `while let`. + (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), + // Allows `cfg(target_vendor = "...")`. + (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), + // Allows `extern crate self as foo;`. + // This puts local crate root into extern prelude under name `foo`. + (accepted, extern_crate_self, "1.34.0", Some(56409), None), + // Allows arbitrary delimited token streams in non-macro attributes. + (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), + // Allows paths to enum variants on type aliases including `Self`. + (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), + // Allows using `#[repr(align(X))]` on enums with equivalent semantics + // to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. + (accepted, repr_align_enum, "1.37.0", Some(57996), None), + // Allows `const _: TYPE = VALUE`. + (accepted, underscore_const_names, "1.37.0", Some(54912), None), + // Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. + (accepted, async_await, "1.39.0", Some(50547), None), + + // ------------------------------------------------------------------------- + // feature-group-end: accepted features + // ------------------------------------------------------------------------- +); -- cgit 1.4.1-3-g733a5 From 975455b37dcdb6c59e47a289aa2d5f19d63a18f6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Aug 2019 18:41:18 +0200 Subject: syntax: extract `removed.rs` feature gates. --- src/libsyntax/feature_gate.rs | 79 +-------------------------------- src/libsyntax/feature_gate/attr.rs | 1 + src/libsyntax/feature_gate/removed.rs | 82 +++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 77 deletions(-) create mode 100644 src/libsyntax/feature_gate/attr.rs create mode 100644 src/libsyntax/feature_gate/removed.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 32fef2fc8dd..e2fa4b27f28 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -14,6 +14,8 @@ mod accepted; use accepted::ACCEPTED_FEATURES; +mod removed; +use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use AttributeType::*; use AttributeGate::*; @@ -83,20 +85,6 @@ macro_rules! declare_features { } } }; - - ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { - /// Represents unstable features which have since been removed (it was once Active) - const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, $reason)),+ - ]; - }; - - ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { - /// Represents stable features which have since been removed (it was once Accepted) - const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ - ]; - }; } // If you change this, please modify `src/doc/unstable-book` as well. @@ -571,69 +559,6 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::let_chains, ]; -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: removed features - // ------------------------------------------------------------------------- - - (removed, import_shadowing, "1.0.0", None, None, None), - (removed, managed_boxes, "1.0.0", None, None, None), - // Allows use of unary negate on unsigned integers, e.g., -e for e: u8 - (removed, negate_unsigned, "1.0.0", Some(29645), None, None), - (removed, reflect, "1.0.0", Some(27749), None, None), - // A way to temporarily opt out of opt in copy. This will *never* be accepted. - (removed, opt_out_copy, "1.0.0", None, None, None), - (removed, quad_precision_float, "1.0.0", None, None, None), - (removed, struct_inherit, "1.0.0", None, None, None), - (removed, test_removed_feature, "1.0.0", None, None, None), - (removed, visible_private_types, "1.0.0", None, None, None), - (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), - // Allows using items which are missing stability attributes - (removed, unmarked_api, "1.0.0", None, None, None), - (removed, allocator, "1.0.0", None, None, None), - (removed, simd, "1.0.0", Some(27731), None, - Some("removed in favor of `#[repr(simd)]`")), - (removed, advanced_slice_patterns, "1.0.0", Some(62254), None, - Some("merged into `#![feature(slice_patterns)]`")), - (removed, macro_reexport, "1.0.0", Some(29638), None, - Some("subsumed by `pub use`")), - (removed, pushpop_unsafe, "1.2.0", None, None, None), - (removed, needs_allocator, "1.4.0", Some(27389), None, - Some("subsumed by `#![feature(allocator_internals)]`")), - (removed, proc_macro_mod, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_expr, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_non_items, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_gen, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, panic_implementation, "1.28.0", Some(44489), None, - Some("subsumed by `#[panic_handler]`")), - // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. - (removed, custom_derive, "1.32.0", Some(29644), None, - Some("subsumed by `#[proc_macro_derive]`")), - // Paths of the form: `extern::foo::bar` - (removed, extern_in_paths, "1.33.0", Some(55600), None, - Some("subsumed by `::foo::bar` paths")), - (removed, quote, "1.33.0", Some(29601), None, None), - // Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). - (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), - (removed, await_macro, "1.38.0", Some(50547), None, - Some("subsumed by `.await` syntax")), - // Allows defining `existential type`s. - (removed, existential_type, "1.38.0", Some(63063), None, - Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), - - // ------------------------------------------------------------------------- - // feature-group-end: removed features - // ------------------------------------------------------------------------- -); - -declare_features! ( - (stable_removed, no_stack_check, "1.0.0", None, None), -); - // If you change this, please modify `src/doc/unstable-book` as well. You must // move that documentation into the relevant place in the other docs, and // remove the chapter on the flag. diff --git a/src/libsyntax/feature_gate/attr.rs b/src/libsyntax/feature_gate/attr.rs new file mode 100644 index 00000000000..46330df3648 --- /dev/null +++ b/src/libsyntax/feature_gate/attr.rs @@ -0,0 +1 @@ +//! TODO diff --git a/src/libsyntax/feature_gate/removed.rs b/src/libsyntax/feature_gate/removed.rs new file mode 100644 index 00000000000..6ebfeb29f67 --- /dev/null +++ b/src/libsyntax/feature_gate/removed.rs @@ -0,0 +1,82 @@ +//! List of the removed feature gates. + +use crate::symbol::{Symbol, sym}; + +macro_rules! declare_features { + ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { + /// Represents unstable features which have since been removed (it was once Active) + pub const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, $reason)),+ + ]; + }; + + ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { + /// Represents stable features which have since been removed (it was once Accepted) + pub const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, None)),+ + ]; + }; +} + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: removed features + // ------------------------------------------------------------------------- + + (removed, import_shadowing, "1.0.0", None, None, None), + (removed, managed_boxes, "1.0.0", None, None, None), + // Allows use of unary negate on unsigned integers, e.g., -e for e: u8 + (removed, negate_unsigned, "1.0.0", Some(29645), None, None), + (removed, reflect, "1.0.0", Some(27749), None, None), + // A way to temporarily opt out of opt in copy. This will *never* be accepted. + (removed, opt_out_copy, "1.0.0", None, None, None), + (removed, quad_precision_float, "1.0.0", None, None, None), + (removed, struct_inherit, "1.0.0", None, None, None), + (removed, test_removed_feature, "1.0.0", None, None, None), + (removed, visible_private_types, "1.0.0", None, None, None), + (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), + // Allows using items which are missing stability attributes + (removed, unmarked_api, "1.0.0", None, None, None), + (removed, allocator, "1.0.0", None, None, None), + (removed, simd, "1.0.0", Some(27731), None, + Some("removed in favor of `#[repr(simd)]`")), + (removed, advanced_slice_patterns, "1.0.0", Some(62254), None, + Some("merged into `#![feature(slice_patterns)]`")), + (removed, macro_reexport, "1.0.0", Some(29638), None, + Some("subsumed by `pub use`")), + (removed, pushpop_unsafe, "1.2.0", None, None, None), + (removed, needs_allocator, "1.4.0", Some(27389), None, + Some("subsumed by `#![feature(allocator_internals)]`")), + (removed, proc_macro_mod, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_expr, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_non_items, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_gen, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, panic_implementation, "1.28.0", Some(44489), None, + Some("subsumed by `#[panic_handler]`")), + // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. + (removed, custom_derive, "1.32.0", Some(29644), None, + Some("subsumed by `#[proc_macro_derive]`")), + // Paths of the form: `extern::foo::bar` + (removed, extern_in_paths, "1.33.0", Some(55600), None, + Some("subsumed by `::foo::bar` paths")), + (removed, quote, "1.33.0", Some(29601), None, None), + // Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). + (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), + (removed, await_macro, "1.38.0", Some(50547), None, + Some("subsumed by `.await` syntax")), + // Allows defining `existential type`s. + (removed, existential_type, "1.38.0", Some(63063), None, + Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), + + // ------------------------------------------------------------------------- + // feature-group-end: removed features + // ------------------------------------------------------------------------- +); + +declare_features! ( + (stable_removed, no_stack_check, "1.0.0", None, None), +); -- cgit 1.4.1-3-g733a5 From 7afb2a82ecf74e69e4b581558990464301790b90 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Aug 2019 18:50:33 +0200 Subject: syntax: extract `active.rs` feature gates. --- src/libsyntax/feature_gate.rs | 520 +--------------------------------- src/libsyntax/feature_gate/active.rs | 522 +++++++++++++++++++++++++++++++++++ 2 files changed, 525 insertions(+), 517 deletions(-) create mode 100644 src/libsyntax/feature_gate/active.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e2fa4b27f28..f01b3af7af4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -16,6 +16,9 @@ mod accepted; use accepted::ACCEPTED_FEATURES; mod removed; use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; +mod active; +use active::{ACTIVE_FEATURES}; +pub use active::{Features, INCOMPLETE_FEATURES}; use AttributeType::*; use AttributeGate::*; @@ -42,523 +45,6 @@ use lazy_static::lazy_static; use std::env; -macro_rules! set { - ($field: ident) => {{ - fn f(features: &mut Features, _: Span) { - features.$field = true; - } - f as fn(&mut Features, Span) - }} -} - -macro_rules! declare_features { - ($((active, $feature: ident, $ver: expr, $issue: expr, $edition: expr),)+) => { - /// Represents active features that are currently being implemented or - /// currently being considered for addition/removal. - const ACTIVE_FEATURES: - &[(Symbol, &str, Option, Option, fn(&mut Features, Span))] = - &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+]; - - /// A set of features to be used by later passes. - #[derive(Clone)] - pub struct Features { - /// `#![feature]` attrs for language features, for error reporting - pub declared_lang_features: Vec<(Symbol, Span, Option)>, - /// `#![feature]` attrs for non-language (library) features - pub declared_lib_features: Vec<(Symbol, Span)>, - $(pub $feature: bool),+ - } - - impl Features { - pub fn new() -> Features { - Features { - declared_lang_features: Vec::new(), - declared_lib_features: Vec::new(), - $($feature: false),+ - } - } - - pub fn walk_feature_fields(&self, mut f: F) - where F: FnMut(&str, bool) - { - $(f(stringify!($feature), self.$feature);)+ - } - } - }; -} - -// If you change this, please modify `src/doc/unstable-book` as well. -// -// Don't ever remove anything from this list; set them to 'Removed'. -// -// The version numbers here correspond to the version in which the current status -// was set. This is most important for knowing when a particular feature became -// stable (active). -// -// Note that the features are grouped into internal/user-facing and then -// sorted by version inside those groups. This is inforced with tidy. -// -// N.B., `tools/tidy/src/features.rs` parses this information directly out of the -// source, so take care when modifying it. - -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: internal feature gates - // ------------------------------------------------------------------------- - - // no-tracking-issue-start - - // Allows using compiler's own crates. - (active, rustc_private, "1.0.0", Some(27812), None), - - // Allows using the `rust-intrinsic`'s "ABI". - (active, intrinsics, "1.0.0", None, None), - - // Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. - (active, lang_items, "1.0.0", None, None), - - // Allows using the `#[stable]` and `#[unstable]` attributes. - (active, staged_api, "1.0.0", None, None), - - // Allows using `#[allow_internal_unstable]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). - (active, allow_internal_unstable, "1.0.0", None, None), - - // Allows using `#[allow_internal_unsafe]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). - (active, allow_internal_unsafe, "1.0.0", None, None), - - // Allows using the macros: - // + `__diagnostic_used` - // + `__register_diagnostic` - // +`__build_diagnostic_array` - (active, rustc_diagnostic_macros, "1.0.0", None, None), - - // Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which - // lets a function to be `const` when opted into with `#![feature(foo)]`. - (active, rustc_const_unstable, "1.0.0", None, None), - - // no-tracking-issue-end - - // Allows using `#[link_name="llvm.*"]`. - (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - - // Allows using `rustc_*` attributes (RFC 572). - (active, rustc_attrs, "1.0.0", Some(29642), None), - - // Allows using `#[on_unimplemented(..)]` on traits. - (active, on_unimplemented, "1.0.0", Some(29628), None), - - // Allows using the `box $expr` syntax. - (active, box_syntax, "1.0.0", Some(49733), None), - - // Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. - (active, main, "1.0.0", Some(29634), None), - - // Allows using `#[start]` on a function indicating that it is the program entrypoint. - (active, start, "1.0.0", Some(29633), None), - - // Allows using the `#[fundamental]` attribute. - (active, fundamental, "1.0.0", Some(29635), None), - - // Allows using the `rust-call` ABI. - (active, unboxed_closures, "1.0.0", Some(29625), None), - - // Allows using the `#[linkage = ".."]` attribute. - (active, linkage, "1.0.0", Some(29603), None), - - // Allows features specific to OIBIT (auto traits). - (active, optin_builtin_traits, "1.0.0", Some(13231), None), - - // Allows using `box` in patterns (RFC 469). - (active, box_patterns, "1.0.0", Some(29641), None), - - // no-tracking-issue-start - - // Allows using `#[prelude_import]` on glob `use` items. - (active, prelude_import, "1.2.0", None, None), - - // no-tracking-issue-end - - // no-tracking-issue-start - - // Allows using `#[omit_gdb_pretty_printer_section]`. - (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), - - // Allows using the `vectorcall` ABI. - (active, abi_vectorcall, "1.7.0", None, None), - - // no-tracking-issue-end - - // Allows using `#[structural_match]` which indicates that a type is structurally matchable. - (active, structural_match, "1.8.0", Some(31434), None), - - // Allows using the `may_dangle` attribute (RFC 1327). - (active, dropck_eyepatch, "1.10.0", Some(34761), None), - - // Allows using the `#![panic_runtime]` attribute. - (active, panic_runtime, "1.10.0", Some(32837), None), - - // Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. - (active, needs_panic_runtime, "1.10.0", Some(32837), None), - - // no-tracking-issue-start - - // Allows identifying the `compiler_builtins` crate. - (active, compiler_builtins, "1.13.0", None, None), - - // Allows using the `unadjusted` ABI; perma-unstable. - (active, abi_unadjusted, "1.16.0", None, None), - - // Allows identifying crates that contain sanitizer runtimes. - (active, sanitizer_runtime, "1.17.0", None, None), - - // Used to identify crates that contain the profiler runtime. - (active, profiler_runtime, "1.18.0", None, None), - - // Allows using the `thiscall` ABI. - (active, abi_thiscall, "1.19.0", None, None), - - // Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. - (active, allocator_internals, "1.20.0", None, None), - - // no-tracking-issue-end - - // Added for testing E0705; perma-unstable. - (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), - - // ------------------------------------------------------------------------- - // feature-group-end: internal feature gates - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: actual feature gates (target features) - // ------------------------------------------------------------------------- - - // FIXME: Document these and merge with the list below. - - // Unstable `#[target_feature]` directives. - (active, arm_target_feature, "1.27.0", Some(44839), None), - (active, aarch64_target_feature, "1.27.0", Some(44839), None), - (active, hexagon_target_feature, "1.27.0", Some(44839), None), - (active, powerpc_target_feature, "1.27.0", Some(44839), None), - (active, mips_target_feature, "1.27.0", Some(44839), None), - (active, avx512_target_feature, "1.27.0", Some(44839), None), - (active, mmx_target_feature, "1.27.0", Some(44839), None), - (active, sse4a_target_feature, "1.27.0", Some(44839), None), - (active, tbm_target_feature, "1.27.0", Some(44839), None), - (active, wasm_target_feature, "1.30.0", Some(44839), None), - (active, adx_target_feature, "1.32.0", Some(44839), None), - (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), - (active, movbe_target_feature, "1.34.0", Some(44839), None), - (active, rtm_target_feature, "1.35.0", Some(44839), None), - (active, f16c_target_feature, "1.36.0", Some(44839), None), - - // ------------------------------------------------------------------------- - // feature-group-end: actual feature gates (target features) - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: actual feature gates - // ------------------------------------------------------------------------- - - // Allows using the `#[link_args]` attribute. - (active, link_args, "1.0.0", Some(29596), None), - - // Allows defining identifiers beyond ASCII. - (active, non_ascii_idents, "1.0.0", Some(55467), None), - - // Allows using `#[plugin_registrar]` on functions. - (active, plugin_registrar, "1.0.0", Some(29597), None), - - // Allows using `#![plugin(myplugin)]`. - (active, plugin, "1.0.0", Some(29597), None), - - // Allows using `#[thread_local]` on `static` items. - (active, thread_local, "1.0.0", Some(29594), None), - - // Allows the use of SIMD types in functions declared in `extern` blocks. - (active, simd_ffi, "1.0.0", Some(27731), None), - - // Allows using custom attributes (RFC 572). - (active, custom_attribute, "1.0.0", Some(29642), None), - - // Allows using non lexical lifetimes (RFC 2094). - (active, nll, "1.0.0", Some(43234), None), - - // Allows using slice patterns. - (active, slice_patterns, "1.0.0", Some(62254), None), - - // Allows the definition of `const` functions with some advanced features. - (active, const_fn, "1.2.0", Some(57563), None), - - // Allows associated type defaults. - (active, associated_type_defaults, "1.2.0", Some(29661), None), - - // Allows `#![no_core]`. - (active, no_core, "1.3.0", Some(29639), None), - - // Allows default type parameters to influence type inference. - (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), - - // Allows `repr(simd)` and importing the various simd intrinsics. - (active, repr_simd, "1.4.0", Some(27731), None), - - // Allows `extern "platform-intrinsic" { ... }`. - (active, platform_intrinsics, "1.4.0", Some(27731), None), - - // Allows `#[unwind(..)]`. - // - // Permits specifying whether a function should permit unwinding or abort on unwind. - (active, unwind_attributes, "1.4.0", Some(58760), None), - - // Allows `#[no_debug]`. - (active, no_debug, "1.5.0", Some(29721), None), - - // Allows attributes on expressions and non-item statements. - (active, stmt_expr_attributes, "1.6.0", Some(15701), None), - - // Allows the use of type ascription in expressions. - (active, type_ascription, "1.6.0", Some(23416), None), - - // Allows `cfg(target_thread_local)`. - (active, cfg_target_thread_local, "1.7.0", Some(29594), None), - - // Allows specialization of implementations (RFC 1210). - (active, specialization, "1.7.0", Some(31844), None), - - // Allows using `#[naked]` on functions. - (active, naked_functions, "1.9.0", Some(32408), None), - - // Allows `cfg(target_has_atomic = "...")`. - (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - - // Allows `X..Y` patterns. - (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - - // Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. - (active, never_type, "1.13.0", Some(35121), None), - - // Allows exhaustive pattern matching on types that contain uninhabited types. - (active, exhaustive_patterns, "1.13.0", Some(51085), None), - - // Allows untagged unions `union U { ... }`. - (active, untagged_unions, "1.13.0", Some(32836), None), - - // Allows `#[link(..., cfg(..))]`. - (active, link_cfg, "1.14.0", Some(37406), None), - - // Allows `extern "ptx-*" fn()`. - (active, abi_ptx, "1.15.0", Some(38788), None), - - // Allows the `#[repr(i128)]` attribute for enums. - (active, repr128, "1.16.0", Some(35118), None), - - // Allows `#[link(kind="static-nobundle"...)]`. - (active, static_nobundle, "1.16.0", Some(37403), None), - - // Allows `extern "msp430-interrupt" fn()`. - (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), - - // Allows declarative macros 2.0 (`macro`). - (active, decl_macro, "1.17.0", Some(39412), None), - - // Allows `extern "x86-interrupt" fn()`. - (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - - // Allows overlapping impls of marker traits. - (active, overlapping_marker_traits, "1.18.0", Some(29864), None), - - // Allows a test to fail without failing the whole suite. - (active, allow_fail, "1.19.0", Some(46488), None), - - // Allows unsized tuple coercion. - (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - - // Allows defining generators. - (active, generators, "1.21.0", Some(43122), None), - - // Allows `#[doc(cfg(...))]`. - (active, doc_cfg, "1.21.0", Some(43781), None), - - // Allows `#[doc(masked)]`. - (active, doc_masked, "1.21.0", Some(44027), None), - - // Allows `#[doc(spotlight)]`. - (active, doc_spotlight, "1.22.0", Some(45040), None), - - // Allows `#[doc(include = "some-file")]`. - (active, external_doc, "1.22.0", Some(44732), None), - - // Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). - (active, non_exhaustive, "1.22.0", Some(44109), None), - - // Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. - (active, crate_visibility_modifier, "1.23.0", Some(53120), None), - - // Allows defining `extern type`s. - (active, extern_types, "1.23.0", Some(43467), None), - - // Allows trait methods with arbitrary self types. - (active, arbitrary_self_types, "1.23.0", Some(44874), None), - - // Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). - (active, in_band_lifetimes, "1.23.0", Some(44524), None), - - // Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). - (active, generic_associated_types, "1.23.0", Some(44265), None), - - // Allows defining `trait X = A + B;` alias items. - (active, trait_alias, "1.24.0", Some(41517), None), - - // Allows infering `'static` outlives requirements (RFC 2093). - (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), - - // Allows macro invocations in `extern {}` blocks. - (active, macros_in_extern, "1.27.0", Some(49476), None), - - // Allows accessing fields of unions inside `const` functions. - (active, const_fn_union, "1.27.0", Some(51909), None), - - // Allows casting raw pointers to `usize` during const eval. - (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), - - // Allows dereferencing raw pointers during const eval. - (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - - // Allows comparing raw pointers during const eval. - (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), - - // Allows `#[doc(alias = "...")]`. - (active, doc_alias, "1.27.0", Some(50146), None), - - // Allows inconsistent bounds in where clauses. - (active, trivial_bounds, "1.28.0", Some(48214), None), - - // Allows `'a: { break 'a; }`. - (active, label_break_value, "1.28.0", Some(48594), None), - - // Allows using `#[doc(keyword = "...")]`. - (active, doc_keyword, "1.28.0", Some(51315), None), - - // Allows reinterpretation of the bits of a value of one type as another type during const eval. - (active, const_transmute, "1.29.0", Some(53605), None), - - // Allows using `try {...}` expressions. - (active, try_blocks, "1.29.0", Some(31436), None), - - // Allows defining an `#[alloc_error_handler]`. - (active, alloc_error_handler, "1.29.0", Some(51540), None), - - // Allows using the `amdgpu-kernel` ABI. - (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - - // Allows panicking during const eval (producing compile-time errors). - (active, const_panic, "1.30.0", Some(51999), None), - - // Allows `#[marker]` on certain traits allowing overlapping implementations. - (active, marker_trait_attr, "1.30.0", Some(29864), None), - - // Allows macro invocations on modules expressions and statements and - // procedural macros to expand to non-items. - (active, proc_macro_hygiene, "1.30.0", Some(54727), None), - - // Allows unsized rvalues at arguments and parameters. - (active, unsized_locals, "1.30.0", Some(48055), None), - - // Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. - (active, custom_test_frameworks, "1.30.0", Some(50297), None), - - // Allows non-builtin attributes in inner attribute position. - (active, custom_inner_attributes, "1.30.0", Some(54726), None), - - // Allows mixing bind-by-move in patterns and references to those identifiers in guards. - (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), - - // Allows `impl Trait` in bindings (`let`, `const`, `static`). - (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), - - // Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. - (active, lint_reasons, "1.31.0", Some(54503), None), - - // Allows exhaustive integer pattern matching on `usize` and `isize`. - (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), - - // Allows relaxing the coherence rules such that - // `impl ForeignTrait for ForeignType is permitted. - (active, re_rebalance_coherence, "1.32.0", Some(55437), None), - - // Allows using `#[ffi_returns_twice]` on foreign functions. - (active, ffi_returns_twice, "1.34.0", Some(58314), None), - - // Allows const generic types (e.g. `struct Foo(...);`). - (active, const_generics, "1.34.0", Some(44580), None), - - // Allows using `#[optimize(X)]`. - (active, optimize_attribute, "1.34.0", Some(54882), None), - - // Allows using C-variadics. - (active, c_variadic, "1.34.0", Some(44930), None), - - // Allows the user of associated type bounds. - (active, associated_type_bounds, "1.34.0", Some(52662), None), - - // Attributes on formal function params. - (active, param_attrs, "1.36.0", Some(60406), None), - - // Allows calling constructor functions in `const fn`. - (active, const_constructor, "1.37.0", Some(61456), None), - - // Allows `if/while p && let q = r && ...` chains. - (active, let_chains, "1.37.0", Some(53667), None), - - // Allows #[repr(transparent)] on enums (RFC 2645). - (active, transparent_enums, "1.37.0", Some(60405), None), - - // Allows #[repr(transparent)] on unions (RFC 2645). - (active, transparent_unions, "1.37.0", Some(60405), None), - - // Allows explicit discriminants on non-unit enum variants. - (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), - - // Allows `impl Trait` with multiple unrelated lifetimes. - (active, member_constraints, "1.37.0", Some(61977), None), - - // Allows `async || body` closures. - (active, async_closure, "1.37.0", Some(62290), None), - - // Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests - (active, cfg_doctest, "1.37.0", Some(62210), None), - - // Allows `[x; N]` where `x` is a constant (RFC 2203). - (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), - - // Allows `impl Trait` to be used inside type aliases (RFC 2515). - (active, type_alias_impl_trait, "1.38.0", Some(63063), None), - - // Allows the use of or-patterns, e.g. `0 | 1`. - (active, or_patterns, "1.38.0", Some(54883), None), - - // ------------------------------------------------------------------------- - // feature-group-end: actual feature gates - // ------------------------------------------------------------------------- -); - -/// Some features are known to be incomplete and using them is likely to have -/// unanticipated results, such as compiler crashes. We warn the user about these -/// to alert them. -pub const INCOMPLETE_FEATURES: &[Symbol] = &[ - sym::impl_trait_in_bindings, - sym::generic_associated_types, - sym::const_generics, - sym::or_patterns, - sym::let_chains, -]; - // If you change this, please modify `src/doc/unstable-book` as well. You must // move that documentation into the relevant place in the other docs, and // remove the chapter on the flag. diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs new file mode 100644 index 00000000000..0bff4ed24a4 --- /dev/null +++ b/src/libsyntax/feature_gate/active.rs @@ -0,0 +1,522 @@ +//! List of the active feature gates. + +use crate::edition::Edition; +use crate::symbol::{Symbol, sym}; +use syntax_pos::Span; + +macro_rules! set { + ($field: ident) => {{ + fn f(features: &mut Features, _: Span) { + features.$field = true; + } + f as fn(&mut Features, Span) + }} +} + +macro_rules! declare_features { + ($((active, $feature: ident, $ver: expr, $issue: expr, $edition: expr),)+) => { + /// Represents active features that are currently being implemented or + /// currently being considered for addition/removal. + pub const ACTIVE_FEATURES: + &[(Symbol, &str, Option, Option, fn(&mut Features, Span))] = + &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+]; + + /// A set of features to be used by later passes. + #[derive(Clone)] + pub struct Features { + /// `#![feature]` attrs for language features, for error reporting + pub declared_lang_features: Vec<(Symbol, Span, Option)>, + /// `#![feature]` attrs for non-language (library) features + pub declared_lib_features: Vec<(Symbol, Span)>, + $(pub $feature: bool),+ + } + + impl Features { + pub fn new() -> Features { + Features { + declared_lang_features: Vec::new(), + declared_lib_features: Vec::new(), + $($feature: false),+ + } + } + + pub fn walk_feature_fields(&self, mut f: F) + where F: FnMut(&str, bool) + { + $(f(stringify!($feature), self.$feature);)+ + } + } + }; +} + +// If you change this, please modify `src/doc/unstable-book` as well. +// +// Don't ever remove anything from this list; move them to `removed.rs`. +// +// The version numbers here correspond to the version in which the current status +// was set. This is most important for knowing when a particular feature became +// stable (active). +// +// Note that the features are grouped into internal/user-facing and then +// sorted by version inside those groups. This is inforced with tidy. +// +// N.B., `tools/tidy/src/features.rs` parses this information directly out of the +// source, so take care when modifying it. + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: internal feature gates + // ------------------------------------------------------------------------- + + // no-tracking-issue-start + + // Allows using compiler's own crates. + (active, rustc_private, "1.0.0", Some(27812), None), + + // Allows using the `rust-intrinsic`'s "ABI". + (active, intrinsics, "1.0.0", None, None), + + // Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. + (active, lang_items, "1.0.0", None, None), + + // Allows using the `#[stable]` and `#[unstable]` attributes. + (active, staged_api, "1.0.0", None, None), + + // Allows using `#[allow_internal_unstable]`. This is an + // attribute on `macro_rules!` and can't use the attribute handling + // below (it has to be checked before expansion possibly makes + // macros disappear). + (active, allow_internal_unstable, "1.0.0", None, None), + + // Allows using `#[allow_internal_unsafe]`. This is an + // attribute on `macro_rules!` and can't use the attribute handling + // below (it has to be checked before expansion possibly makes + // macros disappear). + (active, allow_internal_unsafe, "1.0.0", None, None), + + // Allows using the macros: + // + `__diagnostic_used` + // + `__register_diagnostic` + // +`__build_diagnostic_array` + (active, rustc_diagnostic_macros, "1.0.0", None, None), + + // Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which + // lets a function to be `const` when opted into with `#![feature(foo)]`. + (active, rustc_const_unstable, "1.0.0", None, None), + + // no-tracking-issue-end + + // Allows using `#[link_name="llvm.*"]`. + (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), + + // Allows using `rustc_*` attributes (RFC 572). + (active, rustc_attrs, "1.0.0", Some(29642), None), + + // Allows using `#[on_unimplemented(..)]` on traits. + (active, on_unimplemented, "1.0.0", Some(29628), None), + + // Allows using the `box $expr` syntax. + (active, box_syntax, "1.0.0", Some(49733), None), + + // Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. + (active, main, "1.0.0", Some(29634), None), + + // Allows using `#[start]` on a function indicating that it is the program entrypoint. + (active, start, "1.0.0", Some(29633), None), + + // Allows using the `#[fundamental]` attribute. + (active, fundamental, "1.0.0", Some(29635), None), + + // Allows using the `rust-call` ABI. + (active, unboxed_closures, "1.0.0", Some(29625), None), + + // Allows using the `#[linkage = ".."]` attribute. + (active, linkage, "1.0.0", Some(29603), None), + + // Allows features specific to OIBIT (auto traits). + (active, optin_builtin_traits, "1.0.0", Some(13231), None), + + // Allows using `box` in patterns (RFC 469). + (active, box_patterns, "1.0.0", Some(29641), None), + + // no-tracking-issue-start + + // Allows using `#[prelude_import]` on glob `use` items. + (active, prelude_import, "1.2.0", None, None), + + // no-tracking-issue-end + + // no-tracking-issue-start + + // Allows using `#[omit_gdb_pretty_printer_section]`. + (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), + + // Allows using the `vectorcall` ABI. + (active, abi_vectorcall, "1.7.0", None, None), + + // no-tracking-issue-end + + // Allows using `#[structural_match]` which indicates that a type is structurally matchable. + (active, structural_match, "1.8.0", Some(31434), None), + + // Allows using the `may_dangle` attribute (RFC 1327). + (active, dropck_eyepatch, "1.10.0", Some(34761), None), + + // Allows using the `#![panic_runtime]` attribute. + (active, panic_runtime, "1.10.0", Some(32837), None), + + // Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. + (active, needs_panic_runtime, "1.10.0", Some(32837), None), + + // no-tracking-issue-start + + // Allows identifying the `compiler_builtins` crate. + (active, compiler_builtins, "1.13.0", None, None), + + // Allows using the `unadjusted` ABI; perma-unstable. + (active, abi_unadjusted, "1.16.0", None, None), + + // Allows identifying crates that contain sanitizer runtimes. + (active, sanitizer_runtime, "1.17.0", None, None), + + // Used to identify crates that contain the profiler runtime. + (active, profiler_runtime, "1.18.0", None, None), + + // Allows using the `thiscall` ABI. + (active, abi_thiscall, "1.19.0", None, None), + + // Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. + (active, allocator_internals, "1.20.0", None, None), + + // no-tracking-issue-end + + // Added for testing E0705; perma-unstable. + (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), + + // ------------------------------------------------------------------------- + // feature-group-end: internal feature gates + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // FIXME: Document these and merge with the list below. + + // Unstable `#[target_feature]` directives. + (active, arm_target_feature, "1.27.0", Some(44839), None), + (active, aarch64_target_feature, "1.27.0", Some(44839), None), + (active, hexagon_target_feature, "1.27.0", Some(44839), None), + (active, powerpc_target_feature, "1.27.0", Some(44839), None), + (active, mips_target_feature, "1.27.0", Some(44839), None), + (active, avx512_target_feature, "1.27.0", Some(44839), None), + (active, mmx_target_feature, "1.27.0", Some(44839), None), + (active, sse4a_target_feature, "1.27.0", Some(44839), None), + (active, tbm_target_feature, "1.27.0", Some(44839), None), + (active, wasm_target_feature, "1.30.0", Some(44839), None), + (active, adx_target_feature, "1.32.0", Some(44839), None), + (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), + (active, movbe_target_feature, "1.34.0", Some(44839), None), + (active, rtm_target_feature, "1.35.0", Some(44839), None), + (active, f16c_target_feature, "1.36.0", Some(44839), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates + // ------------------------------------------------------------------------- + + // Allows using the `#[link_args]` attribute. + (active, link_args, "1.0.0", Some(29596), None), + + // Allows defining identifiers beyond ASCII. + (active, non_ascii_idents, "1.0.0", Some(55467), None), + + // Allows using `#[plugin_registrar]` on functions. + (active, plugin_registrar, "1.0.0", Some(29597), None), + + // Allows using `#![plugin(myplugin)]`. + (active, plugin, "1.0.0", Some(29597), None), + + // Allows using `#[thread_local]` on `static` items. + (active, thread_local, "1.0.0", Some(29594), None), + + // Allows the use of SIMD types in functions declared in `extern` blocks. + (active, simd_ffi, "1.0.0", Some(27731), None), + + // Allows using custom attributes (RFC 572). + (active, custom_attribute, "1.0.0", Some(29642), None), + + // Allows using non lexical lifetimes (RFC 2094). + (active, nll, "1.0.0", Some(43234), None), + + // Allows using slice patterns. + (active, slice_patterns, "1.0.0", Some(62254), None), + + // Allows the definition of `const` functions with some advanced features. + (active, const_fn, "1.2.0", Some(57563), None), + + // Allows associated type defaults. + (active, associated_type_defaults, "1.2.0", Some(29661), None), + + // Allows `#![no_core]`. + (active, no_core, "1.3.0", Some(29639), None), + + // Allows default type parameters to influence type inference. + (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), + + // Allows `repr(simd)` and importing the various simd intrinsics. + (active, repr_simd, "1.4.0", Some(27731), None), + + // Allows `extern "platform-intrinsic" { ... }`. + (active, platform_intrinsics, "1.4.0", Some(27731), None), + + // Allows `#[unwind(..)]`. + // + // Permits specifying whether a function should permit unwinding or abort on unwind. + (active, unwind_attributes, "1.4.0", Some(58760), None), + + // Allows `#[no_debug]`. + (active, no_debug, "1.5.0", Some(29721), None), + + // Allows attributes on expressions and non-item statements. + (active, stmt_expr_attributes, "1.6.0", Some(15701), None), + + // Allows the use of type ascription in expressions. + (active, type_ascription, "1.6.0", Some(23416), None), + + // Allows `cfg(target_thread_local)`. + (active, cfg_target_thread_local, "1.7.0", Some(29594), None), + + // Allows specialization of implementations (RFC 1210). + (active, specialization, "1.7.0", Some(31844), None), + + // Allows using `#[naked]` on functions. + (active, naked_functions, "1.9.0", Some(32408), None), + + // Allows `cfg(target_has_atomic = "...")`. + (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), + + // Allows `X..Y` patterns. + (active, exclusive_range_pattern, "1.11.0", Some(37854), None), + + // Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. + (active, never_type, "1.13.0", Some(35121), None), + + // Allows exhaustive pattern matching on types that contain uninhabited types. + (active, exhaustive_patterns, "1.13.0", Some(51085), None), + + // Allows untagged unions `union U { ... }`. + (active, untagged_unions, "1.13.0", Some(32836), None), + + // Allows `#[link(..., cfg(..))]`. + (active, link_cfg, "1.14.0", Some(37406), None), + + // Allows `extern "ptx-*" fn()`. + (active, abi_ptx, "1.15.0", Some(38788), None), + + // Allows the `#[repr(i128)]` attribute for enums. + (active, repr128, "1.16.0", Some(35118), None), + + // Allows `#[link(kind="static-nobundle"...)]`. + (active, static_nobundle, "1.16.0", Some(37403), None), + + // Allows `extern "msp430-interrupt" fn()`. + (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), + + // Allows declarative macros 2.0 (`macro`). + (active, decl_macro, "1.17.0", Some(39412), None), + + // Allows `extern "x86-interrupt" fn()`. + (active, abi_x86_interrupt, "1.17.0", Some(40180), None), + + // Allows overlapping impls of marker traits. + (active, overlapping_marker_traits, "1.18.0", Some(29864), None), + + // Allows a test to fail without failing the whole suite. + (active, allow_fail, "1.19.0", Some(46488), None), + + // Allows unsized tuple coercion. + (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), + + // Allows defining generators. + (active, generators, "1.21.0", Some(43122), None), + + // Allows `#[doc(cfg(...))]`. + (active, doc_cfg, "1.21.0", Some(43781), None), + + // Allows `#[doc(masked)]`. + (active, doc_masked, "1.21.0", Some(44027), None), + + // Allows `#[doc(spotlight)]`. + (active, doc_spotlight, "1.22.0", Some(45040), None), + + // Allows `#[doc(include = "some-file")]`. + (active, external_doc, "1.22.0", Some(44732), None), + + // Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). + (active, non_exhaustive, "1.22.0", Some(44109), None), + + // Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. + (active, crate_visibility_modifier, "1.23.0", Some(53120), None), + + // Allows defining `extern type`s. + (active, extern_types, "1.23.0", Some(43467), None), + + // Allows trait methods with arbitrary self types. + (active, arbitrary_self_types, "1.23.0", Some(44874), None), + + // Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). + (active, in_band_lifetimes, "1.23.0", Some(44524), None), + + // Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). + (active, generic_associated_types, "1.23.0", Some(44265), None), + + // Allows defining `trait X = A + B;` alias items. + (active, trait_alias, "1.24.0", Some(41517), None), + + // Allows infering `'static` outlives requirements (RFC 2093). + (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), + + // Allows macro invocations in `extern {}` blocks. + (active, macros_in_extern, "1.27.0", Some(49476), None), + + // Allows accessing fields of unions inside `const` functions. + (active, const_fn_union, "1.27.0", Some(51909), None), + + // Allows casting raw pointers to `usize` during const eval. + (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), + + // Allows dereferencing raw pointers during const eval. + (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), + + // Allows comparing raw pointers during const eval. + (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), + + // Allows `#[doc(alias = "...")]`. + (active, doc_alias, "1.27.0", Some(50146), None), + + // Allows inconsistent bounds in where clauses. + (active, trivial_bounds, "1.28.0", Some(48214), None), + + // Allows `'a: { break 'a; }`. + (active, label_break_value, "1.28.0", Some(48594), None), + + // Allows using `#[doc(keyword = "...")]`. + (active, doc_keyword, "1.28.0", Some(51315), None), + + // Allows reinterpretation of the bits of a value of one type as another type during const eval. + (active, const_transmute, "1.29.0", Some(53605), None), + + // Allows using `try {...}` expressions. + (active, try_blocks, "1.29.0", Some(31436), None), + + // Allows defining an `#[alloc_error_handler]`. + (active, alloc_error_handler, "1.29.0", Some(51540), None), + + // Allows using the `amdgpu-kernel` ABI. + (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), + + // Allows panicking during const eval (producing compile-time errors). + (active, const_panic, "1.30.0", Some(51999), None), + + // Allows `#[marker]` on certain traits allowing overlapping implementations. + (active, marker_trait_attr, "1.30.0", Some(29864), None), + + // Allows macro invocations on modules expressions and statements and + // procedural macros to expand to non-items. + (active, proc_macro_hygiene, "1.30.0", Some(54727), None), + + // Allows unsized rvalues at arguments and parameters. + (active, unsized_locals, "1.30.0", Some(48055), None), + + // Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. + (active, custom_test_frameworks, "1.30.0", Some(50297), None), + + // Allows non-builtin attributes in inner attribute position. + (active, custom_inner_attributes, "1.30.0", Some(54726), None), + + // Allows mixing bind-by-move in patterns and references to those identifiers in guards. + (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), + + // Allows `impl Trait` in bindings (`let`, `const`, `static`). + (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), + + // Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. + (active, lint_reasons, "1.31.0", Some(54503), None), + + // Allows exhaustive integer pattern matching on `usize` and `isize`. + (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), + + // Allows relaxing the coherence rules such that + // `impl ForeignTrait for ForeignType is permitted. + (active, re_rebalance_coherence, "1.32.0", Some(55437), None), + + // Allows using `#[ffi_returns_twice]` on foreign functions. + (active, ffi_returns_twice, "1.34.0", Some(58314), None), + + // Allows const generic types (e.g. `struct Foo(...);`). + (active, const_generics, "1.34.0", Some(44580), None), + + // Allows using `#[optimize(X)]`. + (active, optimize_attribute, "1.34.0", Some(54882), None), + + // Allows using C-variadics. + (active, c_variadic, "1.34.0", Some(44930), None), + + // Allows the user of associated type bounds. + (active, associated_type_bounds, "1.34.0", Some(52662), None), + + // Attributes on formal function params. + (active, param_attrs, "1.36.0", Some(60406), None), + + // Allows calling constructor functions in `const fn`. + (active, const_constructor, "1.37.0", Some(61456), None), + + // Allows `if/while p && let q = r && ...` chains. + (active, let_chains, "1.37.0", Some(53667), None), + + // Allows #[repr(transparent)] on enums (RFC 2645). + (active, transparent_enums, "1.37.0", Some(60405), None), + + // Allows #[repr(transparent)] on unions (RFC 2645). + (active, transparent_unions, "1.37.0", Some(60405), None), + + // Allows explicit discriminants on non-unit enum variants. + (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), + + // Allows `impl Trait` with multiple unrelated lifetimes. + (active, member_constraints, "1.37.0", Some(61977), None), + + // Allows `async || body` closures. + (active, async_closure, "1.37.0", Some(62290), None), + + // Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests + (active, cfg_doctest, "1.37.0", Some(62210), None), + + // Allows `[x; N]` where `x` is a constant (RFC 2203). + (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), + + // Allows `impl Trait` to be used inside type aliases (RFC 2515). + (active, type_alias_impl_trait, "1.38.0", Some(63063), None), + + // Allows the use of or-patterns, e.g. `0 | 1`. + (active, or_patterns, "1.38.0", Some(54883), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates + // ------------------------------------------------------------------------- +); + +/// Some features are known to be incomplete and using them is likely to have +/// unanticipated results, such as compiler crashes. We warn the user about these +/// to alert them. +pub const INCOMPLETE_FEATURES: &[Symbol] = &[ + sym::impl_trait_in_bindings, + sym::generic_associated_types, + sym::const_generics, + sym::or_patterns, + sym::let_chains, +]; -- cgit 1.4.1-3-g733a5 From 332a77e6212ccb96800c70d864a20aecce789136 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Aug 2019 18:32:31 +0200 Subject: syntax: extract `builin_attrs.rs`. --- src/libsyntax/feature_gate.rs | 722 +-------------------------- src/libsyntax/feature_gate/attr.rs | 1 - src/libsyntax/feature_gate/builtin_attrs.rs | 724 ++++++++++++++++++++++++++++ 3 files changed, 732 insertions(+), 715 deletions(-) delete mode 100644 src/libsyntax/feature_gate/attr.rs create mode 100644 src/libsyntax/feature_gate/builtin_attrs.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index f01b3af7af4..0e04d4c6c23 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -19,15 +19,18 @@ use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; mod active; use active::{ACTIVE_FEATURES}; pub use active::{Features, INCOMPLETE_FEATURES}; - -use AttributeType::*; -use AttributeGate::*; +mod builtin_attrs; +pub use builtin_attrs::{ + AttributeGate, AttributeType, GatedCfg, + BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + deprecated_attributes, is_builtin_attr, is_builtin_attr_name, +}; use crate::ast::{ self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd, }; -use crate::attr::{self, check_builtin_attribute, AttributeTemplate}; +use crate::attr::{self, check_builtin_attribute}; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; @@ -41,67 +44,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_target::spec::abi::Abi; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use log::debug; -use lazy_static::lazy_static; use std::env; -// If you change this, please modify `src/doc/unstable-book` as well. You must -// move that documentation into the relevant place in the other docs, and -// remove the chapter on the flag. - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum AttributeType { - /// Normal, builtin attribute that is consumed - /// by the compiler before the unused_attribute check - Normal, - - /// Builtin attribute that may not be consumed by the compiler - /// before the unused_attribute check. These attributes - /// will be ignored by the unused_attribute lint - Whitelisted, - - /// Builtin attribute that is only allowed at the crate level - CrateLevel, -} - -pub enum AttributeGate { - /// Is gated by a given feature gate, reason - /// and function to check if enabled - Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), - - /// Ungated attribute, can be used on all release channels - Ungated, -} - -/// A convenience macro for constructing attribute templates. -/// E.g., `template!(Word, List: "description")` means that the attribute -/// supports forms `#[attr]` and `#[attr(description)]`. -macro_rules! template { - (Word) => { template!(@ true, None, None) }; - (List: $descr: expr) => { template!(@ false, Some($descr), None) }; - (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) }; - (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) }; - (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) }; - (List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ false, Some($descr1), Some($descr2)) - }; - (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ true, Some($descr1), Some($descr2)) - }; - (@ $word: expr, $list: expr, $name_value_str: expr) => { AttributeTemplate { - word: $word, list: $list, name_value_str: $name_value_str - } }; -} - -impl AttributeGate { - fn is_deprecated(&self) -> bool { - match *self { - Gated(Stability::Deprecated(_, _), ..) => true, - _ => false, - } - } -} - #[derive(Copy, Clone, Debug)] pub enum Stability { Unstable, @@ -110,657 +55,6 @@ pub enum Stability { Deprecated(&'static str, Option<&'static str>), } -// fn() is not Debug -impl std::fmt::Debug for AttributeGate { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - Gated(ref stab, name, expl, _) => - write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), - Ungated => write!(fmt, "Ungated") - } - } -} - -macro_rules! cfg_fn { - ($field: ident) => {{ - fn f(features: &Features) -> bool { - features.$field - } - f as fn(&Features) -> bool - }} -} - -pub fn deprecated_attributes() -> Vec<&'static (Symbol, AttributeType, - AttributeTemplate, AttributeGate)> { - BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() -} - -pub fn is_builtin_attr_name(name: ast::Name) -> bool { - BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() -} - -pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some() -} - -/// Attributes that have a special meaning to rustc or rustdoc -pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ - // Normal attributes - - ( - sym::warn, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::allow, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::forbid, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::deny, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - - (sym::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated), - (sym::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated), - (sym::plugin_registrar, Normal, template!(Word), Ungated), - - (sym::cfg, Normal, template!(List: "predicate"), Ungated), - (sym::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), - (sym::main, Normal, template!(Word), Ungated), - (sym::start, Normal, template!(Word), Ungated), - (sym::repr, Normal, template!(List: "C, packed, ..."), Ungated), - (sym::path, Normal, template!(NameValueStr: "file"), Ungated), - (sym::automatically_derived, Normal, template!(Word), Ungated), - (sym::no_mangle, Whitelisted, template!(Word), Ungated), - (sym::no_link, Normal, template!(Word), Ungated), - (sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated), - ( - sym::should_panic, - Normal, - template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), - Ungated - ), - (sym::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated), - (sym::no_implicit_prelude, Normal, template!(Word), Ungated), - (sym::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated), - (sym::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, - sym::link_args, - "the `link_args` attribute is experimental and not \ - portable across platforms, it is recommended to \ - use `#[link(name = \"foo\")] instead", - cfg_fn!(link_args))), - (sym::macro_escape, Normal, template!(Word), Ungated), - - // RFC #1445. - (sym::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::structural_match, - "the semantics of constant patterns is \ - not yet settled", - cfg_fn!(structural_match))), - - // RFC #2008 - (sym::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::non_exhaustive, - "non exhaustive is an experimental feature", - cfg_fn!(non_exhaustive))), - - // RFC #1268 - (sym::marker, Normal, template!(Word), Gated(Stability::Unstable, - sym::marker_trait_attr, - "marker traits is an experimental feature", - cfg_fn!(marker_trait_attr))), - - (sym::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, - sym::plugin, - "compiler plugins are experimental \ - and possibly buggy", - cfg_fn!(plugin))), - - (sym::no_std, CrateLevel, template!(Word), Ungated), - (sym::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable, - sym::no_core, - "no_core is experimental", - cfg_fn!(no_core))), - (sym::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, - sym::lang_items, - "language items are subject to change", - cfg_fn!(lang_items))), - (sym::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), - Gated(Stability::Unstable, - sym::linkage, - "the `linkage` attribute is experimental \ - and not portable across platforms", - cfg_fn!(linkage))), - (sym::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::thread_local, - "`#[thread_local]` is an experimental feature, and does \ - not currently handle destructors", - cfg_fn!(thread_local))), - - (sym::rustc_on_unimplemented, Whitelisted, template!(List: - r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, - NameValueStr: "message"), - Gated(Stability::Unstable, - sym::on_unimplemented, - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature", - cfg_fn!(on_unimplemented))), - (sym::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), - Gated(Stability::Unstable, - sym::rustc_const_unstable, - "the `#[rustc_const_unstable]` attribute \ - is an internal feature", - cfg_fn!(rustc_const_unstable))), - (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::allocator_internals, - "the `#[default_lib_allocator]` \ - attribute is an experimental feature", - cfg_fn!(allocator_internals))), - (sym::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable, - sym::allocator_internals, - "the `#[needs_allocator]` \ - attribute is an experimental \ - feature", - cfg_fn!(allocator_internals))), - (sym::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::panic_runtime, - "the `#[panic_runtime]` attribute is \ - an experimental feature", - cfg_fn!(panic_runtime))), - (sym::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::needs_panic_runtime, - "the `#[needs_panic_runtime]` \ - attribute is an experimental \ - feature", - cfg_fn!(needs_panic_runtime))), - (sym::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_outlives]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_variance]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout, Normal, template!(List: "field1, field2, ..."), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout_scalar_valid_range_start]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout_scalar_valid_range_end]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_nonnull_optimization_guaranteed]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_regions]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_error]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", - /*opt*/ except = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dirty]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", - /*opt*/ except = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_clean]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ( - sym::rustc_partition_reused, - Whitelisted, - template!(List: r#"cfg = "...", module = "...""#), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs) - ) - ), - ( - sym::rustc_partition_codegened, - Whitelisted, - template!(List: r#"cfg = "...", module = "...""#), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs), - ) - ), - (sym::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...", - kind = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_mir]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ( - sym::rustc_inherit_overflow_checks, - Whitelisted, - template!(Word), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_inherit_overflow_checks]` \ - attribute is just used to control \ - overflow checking behavior of several \ - libcore functions that are inlined \ - across crates and will never be stable", - cfg_fn!(rustc_attrs), - ) - ), - - (sym::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dump_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dump_env_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dump_env_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_object_lifetime_default, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_object_lifetime_default]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_test_marker]` attribute \ - is used internally to track tests", - cfg_fn!(rustc_attrs))), - (sym::rustc_macro_transparency, Whitelisted, template!(NameValueStr: - "transparent|semitransparent|opaque"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "used internally for testing macro hygiene", - cfg_fn!(rustc_attrs))), - (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::compiler_builtins, - "the `#[compiler_builtins]` attribute is used to \ - identify the `compiler_builtins` crate which \ - contains compiler-rt intrinsics and will never be \ - stable", - cfg_fn!(compiler_builtins))), - (sym::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::sanitizer_runtime, - "the `#[sanitizer_runtime]` attribute is used to \ - identify crates that contain the runtime of a \ - sanitizer and will never be stable", - cfg_fn!(sanitizer_runtime))), - (sym::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::profiler_runtime, - "the `#[profiler_runtime]` attribute is used to \ - identify the `profiler_builtins` crate which \ - contains the profiler runtime and will never be \ - stable", - cfg_fn!(profiler_runtime))), - - (sym::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), - Gated(Stability::Unstable, - sym::allow_internal_unstable, - EXPLAIN_ALLOW_INTERNAL_UNSTABLE, - cfg_fn!(allow_internal_unstable))), - - (sym::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable, - sym::allow_internal_unsafe, - EXPLAIN_ALLOW_INTERNAL_UNSAFE, - cfg_fn!(allow_internal_unsafe))), - - (sym::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::fundamental, - "the `#[fundamental]` attribute \ - is an experimental feature", - cfg_fn!(fundamental))), - - (sym::proc_macro_derive, Normal, template!(List: "TraitName, \ - /*opt*/ attributes(name1, name2, ...)"), - Ungated), - - (sym::rustc_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_allocator_nounwind, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_builtin_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_promotable, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_allow_const_fn_ptr, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_dummy, Normal, template!(Word /* doesn't matter*/), Gated(Stability::Unstable, - sym::rustc_attrs, - "used by the test suite", - cfg_fn!(rustc_attrs))), - - // FIXME: #14408 whitelist docs since rustdoc looks at them - ( - sym::doc, - Whitelisted, - template!(List: "hidden|inline|...", NameValueStr: "string"), - Ungated - ), - - // FIXME: #14406 these are processed in codegen, which happens after the - // lint pass - (sym::cold, Whitelisted, template!(Word), Ungated), - (sym::naked, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::naked_functions, - "the `#[naked]` attribute \ - is an experimental feature", - cfg_fn!(naked_functions))), - (sym::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::ffi_returns_twice, - "the `#[ffi_returns_twice]` attribute \ - is an experimental feature", - cfg_fn!(ffi_returns_twice))), - (sym::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated), - (sym::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::inline, Whitelisted, template!(Word, List: "always|never"), Ungated), - (sym::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...""#), Ungated), - (sym::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::no_builtins, Whitelisted, template!(Word), Ungated), - (sym::no_debug, Whitelisted, template!(Word), Gated( - Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), - sym::no_debug, - "the `#[no_debug]` attribute was an experimental feature that has been \ - deprecated due to lack of demand", - cfg_fn!(no_debug))), - ( - sym::omit_gdb_pretty_printer_section, - Whitelisted, - template!(Word), - Gated( - Stability::Unstable, - sym::omit_gdb_pretty_printer_section, - "the `#[omit_gdb_pretty_printer_section]` \ - attribute is just used for the Rust test \ - suite", - cfg_fn!(omit_gdb_pretty_printer_section) - ) - ), - (sym::may_dangle, - Normal, - template!(Word), - Gated(Stability::Unstable, - sym::dropck_eyepatch, - "`may_dangle` has unstable semantics and may be removed in the future", - cfg_fn!(dropck_eyepatch))), - (sym::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable, - sym::unwind_attributes, - "`#[unwind]` is experimental", - cfg_fn!(unwind_attributes))), - (sym::used, Whitelisted, template!(Word), Ungated), - - // used in resolve - (sym::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::prelude_import, - "`#[prelude_import]` is for use by rustc only", - cfg_fn!(prelude_import))), - - // FIXME: #14407 these are only looked at on-demand so we can't - // guarantee they'll have already been checked - ( - sym::rustc_deprecated, - Whitelisted, - template!(List: r#"since = "version", reason = "...""#), - Ungated - ), - (sym::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), - ( - sym::stable, - Whitelisted, - template!(List: r#"feature = "name", since = "version""#), - Ungated - ), - ( - sym::unstable, - Whitelisted, - template!(List: r#"feature = "name", reason = "...", issue = "N""#), - Ungated - ), - (sym::deprecated, - Normal, - template!( - Word, - List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, - NameValueStr: "reason" - ), - Ungated - ), - - (sym::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable, - sym::unboxed_closures, - "unboxed_closures are still evolving", - cfg_fn!(unboxed_closures))), - - (sym::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated), - - (sym::proc_macro_attribute, Normal, template!(Word), Ungated), - (sym::proc_macro, Normal, template!(Word), Ungated), - - (sym::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "used internally by rustc", - cfg_fn!(rustc_attrs))), - - (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, - sym::allow_fail, - "allow_fail attribute is currently unstable", - cfg_fn!(allow_fail))), - - (sym::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), - - // whitelists "identity-like" conversion methods to suggest on type mismatch - (sym::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), - - ( - sym::rustc_args_required_const, - Whitelisted, - template!(List: "N"), - Gated(Stability::Unstable, sym::rustc_attrs, "never will be stable", - cfg_fn!(rustc_attrs)) - ), - // RFC 2070 - (sym::panic_handler, Normal, template!(Word), Ungated), - - (sym::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable, - sym::alloc_error_handler, - "`#[alloc_error_handler]` is an unstable feature", - cfg_fn!(alloc_error_handler))), - - // RFC 2412 - (sym::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, - sym::optimize_attribute, - "`#[optimize]` attribute is an unstable feature", - cfg_fn!(optimize_attribute))), - - // Crate level attributes - (sym::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated), - (sym::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), - (sym::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated), - (sym::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated), - (sym::no_start, CrateLevel, template!(Word), Ungated), - (sym::no_main, CrateLevel, template!(Word), Ungated), - (sym::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable, - sym::custom_test_frameworks, - "custom test frameworks are an unstable feature", - cfg_fn!(custom_test_frameworks))), -]; - -pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); - -lazy_static! { - pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { - let mut map = FxHashMap::default(); - for attr in BUILTIN_ATTRIBUTES.iter() { - if map.insert(attr.0, attr).is_some() { - panic!("duplicate builtin attribute `{}`", attr.0); - } - } - map - }; -} - -// cfg(...)'s that are feature gated -const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[ - // (name in cfg, feature, function to check if the feature is enabled) - (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), - (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), - (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), - (sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)), -]; - -#[derive(Debug)] -pub struct GatedCfg { - span: Span, - index: usize, -} - -impl GatedCfg { - pub fn gate(cfg: &ast::MetaItem) -> Option { - GATED_CFGS.iter() - .position(|info| cfg.check_name(info.0)) - .map(|idx| { - GatedCfg { - span: cfg.span, - index: idx - } - }) - } - - pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { - let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !self.span.allows_unstable(feature) { - let explain = format!("`cfg({})` is experimental and subject to change", cfg); - emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); - } - } -} - struct Context<'a> { features: &'a Features, parse_sess: &'a ParseSess, @@ -800,7 +94,7 @@ impl<'a> Context<'a> { ) { debug!("check_attribute(attr = {:?})", attr); if let Some(&(name, ty, _template, ref gateage)) = attr_info { - if let Gated(_, name, desc, ref has_feature) = *gateage { + if let AttributeGate::Gated(_, name, desc, ref has_feature) = *gateage { if !attr.span.allows_unstable(name) { gate_feature_fn!( self, has_feature, attr.span, name, desc, GateStrength::Hard diff --git a/src/libsyntax/feature_gate/attr.rs b/src/libsyntax/feature_gate/attr.rs deleted file mode 100644 index 46330df3648..00000000000 --- a/src/libsyntax/feature_gate/attr.rs +++ /dev/null @@ -1 +0,0 @@ -//! TODO diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs new file mode 100644 index 00000000000..17e58df89e1 --- /dev/null +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -0,0 +1,724 @@ +//! Built-in attributes and `cfg` flag gating. + +use AttributeType::*; +use AttributeGate::*; + +use super::{emit_feature_err, GateIssue}; +use super::{Stability, EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE}; +use super::active::Features; + +use crate::ast; +use crate::attr::AttributeTemplate; +use crate::symbol::{Symbol, sym}; +use crate::parse::ParseSess; + +use syntax_pos::Span; +use rustc_data_structures::fx::FxHashMap; +use lazy_static::lazy_static; + +macro_rules! cfg_fn { + ($field: ident) => {{ + fn f(features: &Features) -> bool { + features.$field + } + f as fn(&Features) -> bool + }} +} + +// cfg(...)'s that are feature gated +const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[ + // (name in cfg, feature, function to check if the feature is enabled) + (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), + (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), + (sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)), +]; + +#[derive(Debug)] +pub struct GatedCfg { + span: Span, + index: usize, +} + +impl GatedCfg { + pub fn gate(cfg: &ast::MetaItem) -> Option { + GATED_CFGS.iter() + .position(|info| cfg.check_name(info.0)) + .map(|idx| { + GatedCfg { + span: cfg.span, + index: idx + } + }) + } + + pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { + let (cfg, feature, has_feature) = GATED_CFGS[self.index]; + if !has_feature(features) && !self.span.allows_unstable(feature) { + let explain = format!("`cfg({})` is experimental and subject to change", cfg); + emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); + } + } +} + +// If you change this, please modify `src/doc/unstable-book` as well. You must +// move that documentation into the relevant place in the other docs, and +// remove the chapter on the flag. + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AttributeType { + /// Normal, builtin attribute that is consumed + /// by the compiler before the unused_attribute check + Normal, + + /// Builtin attribute that may not be consumed by the compiler + /// before the unused_attribute check. These attributes + /// will be ignored by the unused_attribute lint + Whitelisted, + + /// Builtin attribute that is only allowed at the crate level + CrateLevel, +} + +pub enum AttributeGate { + /// Is gated by a given feature gate, reason + /// and function to check if enabled + Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), + + /// Ungated attribute, can be used on all release channels + Ungated, +} + +// fn() is not Debug +impl std::fmt::Debug for AttributeGate { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Self::Gated(ref stab, name, expl, _) => + write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), + Self::Ungated => write!(fmt, "Ungated") + } + } +} + +impl AttributeGate { + fn is_deprecated(&self) -> bool { + match *self { + Self::Gated(Stability::Deprecated(_, _), ..) => true, + _ => false, + } + } +} + +/// A convenience macro for constructing attribute templates. +/// E.g., `template!(Word, List: "description")` means that the attribute +/// supports forms `#[attr]` and `#[attr(description)]`. +macro_rules! template { + (Word) => { template!(@ true, None, None) }; + (List: $descr: expr) => { template!(@ false, Some($descr), None) }; + (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) }; + (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) }; + (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) }; + (List: $descr1: expr, NameValueStr: $descr2: expr) => { + template!(@ false, Some($descr1), Some($descr2)) + }; + (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { + template!(@ true, Some($descr1), Some($descr2)) + }; + (@ $word: expr, $list: expr, $name_value_str: expr) => { AttributeTemplate { + word: $word, list: $list, name_value_str: $name_value_str + } }; +} + +pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); + +/// Attributes that have a special meaning to rustc or rustdoc +pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ + // Normal attributes + + ( + sym::warn, + Normal, + template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + Ungated + ), + ( + sym::allow, + Normal, + template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + Ungated + ), + ( + sym::forbid, + Normal, + template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + Ungated + ), + ( + sym::deny, + Normal, + template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + Ungated + ), + + (sym::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated), + (sym::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated), + (sym::plugin_registrar, Normal, template!(Word), Ungated), + + (sym::cfg, Normal, template!(List: "predicate"), Ungated), + (sym::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), + (sym::main, Normal, template!(Word), Ungated), + (sym::start, Normal, template!(Word), Ungated), + (sym::repr, Normal, template!(List: "C, packed, ..."), Ungated), + (sym::path, Normal, template!(NameValueStr: "file"), Ungated), + (sym::automatically_derived, Normal, template!(Word), Ungated), + (sym::no_mangle, Whitelisted, template!(Word), Ungated), + (sym::no_link, Normal, template!(Word), Ungated), + (sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated), + ( + sym::should_panic, + Normal, + template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), + Ungated + ), + (sym::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated), + (sym::no_implicit_prelude, Normal, template!(Word), Ungated), + (sym::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated), + (sym::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, + sym::link_args, + "the `link_args` attribute is experimental and not \ + portable across platforms, it is recommended to \ + use `#[link(name = \"foo\")] instead", + cfg_fn!(link_args))), + (sym::macro_escape, Normal, template!(Word), Ungated), + + // RFC #1445. + (sym::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::structural_match, + "the semantics of constant patterns is \ + not yet settled", + cfg_fn!(structural_match))), + + // RFC #2008 + (sym::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::non_exhaustive, + "non exhaustive is an experimental feature", + cfg_fn!(non_exhaustive))), + + // RFC #1268 + (sym::marker, Normal, template!(Word), Gated(Stability::Unstable, + sym::marker_trait_attr, + "marker traits is an experimental feature", + cfg_fn!(marker_trait_attr))), + + (sym::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, + sym::plugin, + "compiler plugins are experimental \ + and possibly buggy", + cfg_fn!(plugin))), + + (sym::no_std, CrateLevel, template!(Word), Ungated), + (sym::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable, + sym::no_core, + "no_core is experimental", + cfg_fn!(no_core))), + (sym::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, + sym::lang_items, + "language items are subject to change", + cfg_fn!(lang_items))), + (sym::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), + Gated(Stability::Unstable, + sym::linkage, + "the `linkage` attribute is experimental \ + and not portable across platforms", + cfg_fn!(linkage))), + (sym::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::thread_local, + "`#[thread_local]` is an experimental feature, and does \ + not currently handle destructors", + cfg_fn!(thread_local))), + + (sym::rustc_on_unimplemented, Whitelisted, template!(List: + r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, + NameValueStr: "message"), + Gated(Stability::Unstable, + sym::on_unimplemented, + "the `#[rustc_on_unimplemented]` attribute \ + is an experimental feature", + cfg_fn!(on_unimplemented))), + (sym::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), + Gated(Stability::Unstable, + sym::rustc_const_unstable, + "the `#[rustc_const_unstable]` attribute \ + is an internal feature", + cfg_fn!(rustc_const_unstable))), + (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::allocator_internals, + "the `#[default_lib_allocator]` \ + attribute is an experimental feature", + cfg_fn!(allocator_internals))), + (sym::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable, + sym::allocator_internals, + "the `#[needs_allocator]` \ + attribute is an experimental \ + feature", + cfg_fn!(allocator_internals))), + (sym::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::panic_runtime, + "the `#[panic_runtime]` attribute is \ + an experimental feature", + cfg_fn!(panic_runtime))), + (sym::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::needs_panic_runtime, + "the `#[needs_panic_runtime]` \ + attribute is an experimental \ + feature", + cfg_fn!(needs_panic_runtime))), + (sym::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_outlives]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_variance]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_layout, Normal, template!(List: "field1, field2, ..."), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_layout]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_layout_scalar_valid_range_start]` attribute \ + is just used to enable niche optimizations in libcore \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_layout_scalar_valid_range_end]` attribute \ + is just used to enable niche optimizations in libcore \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_nonnull_optimization_guaranteed]` attribute \ + is just used to enable niche optimizations in libcore \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_regions]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_error]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_if_this_changed]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_if_this_changed]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", + /*opt*/ except = "...""#), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_dirty]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", + /*opt*/ except = "...""#), + Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_clean]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + ( + sym::rustc_partition_reused, + Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs) + ) + ), + ( + sym::rustc_partition_codegened, + Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs), + ) + ), + (sym::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...", + kind = "...""#), + Gated(Stability::Unstable, + sym::rustc_attrs, + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal rustc attributes will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal rustc attributes will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_mir]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + ( + sym::rustc_inherit_overflow_checks, + Whitelisted, + template!(Word), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_inherit_overflow_checks]` \ + attribute is just used to control \ + overflow checking behavior of several \ + libcore functions that are inlined \ + across crates and will never be stable", + cfg_fn!(rustc_attrs), + ) + ), + + (sym::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_dump_program_clauses]` \ + attribute is just used for rustc unit \ + tests and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_dump_env_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_dump_env_program_clauses]` \ + attribute is just used for rustc unit \ + tests and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_object_lifetime_default, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_object_lifetime_default]` \ + attribute is just used for rustc unit \ + tests and will never be stable", + cfg_fn!(rustc_attrs))), + (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "the `#[rustc_test_marker]` attribute \ + is used internally to track tests", + cfg_fn!(rustc_attrs))), + (sym::rustc_macro_transparency, Whitelisted, template!(NameValueStr: + "transparent|semitransparent|opaque"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "used internally for testing macro hygiene", + cfg_fn!(rustc_attrs))), + (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::compiler_builtins, + "the `#[compiler_builtins]` attribute is used to \ + identify the `compiler_builtins` crate which \ + contains compiler-rt intrinsics and will never be \ + stable", + cfg_fn!(compiler_builtins))), + (sym::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::sanitizer_runtime, + "the `#[sanitizer_runtime]` attribute is used to \ + identify crates that contain the runtime of a \ + sanitizer and will never be stable", + cfg_fn!(sanitizer_runtime))), + (sym::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::profiler_runtime, + "the `#[profiler_runtime]` attribute is used to \ + identify the `profiler_builtins` crate which \ + contains the profiler runtime and will never be \ + stable", + cfg_fn!(profiler_runtime))), + + (sym::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + Gated(Stability::Unstable, + sym::allow_internal_unstable, + EXPLAIN_ALLOW_INTERNAL_UNSTABLE, + cfg_fn!(allow_internal_unstable))), + + (sym::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable, + sym::allow_internal_unsafe, + EXPLAIN_ALLOW_INTERNAL_UNSAFE, + cfg_fn!(allow_internal_unsafe))), + + (sym::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::fundamental, + "the `#[fundamental]` attribute \ + is an experimental feature", + cfg_fn!(fundamental))), + + (sym::proc_macro_derive, Normal, template!(List: "TraitName, \ + /*opt*/ attributes(name1, name2, ...)"), + Ungated), + + (sym::rustc_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_allocator_nounwind, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_builtin_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_promotable, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_allow_const_fn_ptr, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal implementation detail", + cfg_fn!(rustc_attrs))), + + (sym::rustc_dummy, Normal, template!(Word /* doesn't matter*/), Gated(Stability::Unstable, + sym::rustc_attrs, + "used by the test suite", + cfg_fn!(rustc_attrs))), + + // FIXME: #14408 whitelist docs since rustdoc looks at them + ( + sym::doc, + Whitelisted, + template!(List: "hidden|inline|...", NameValueStr: "string"), + Ungated + ), + + // FIXME: #14406 these are processed in codegen, which happens after the + // lint pass + (sym::cold, Whitelisted, template!(Word), Ungated), + (sym::naked, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::naked_functions, + "the `#[naked]` attribute \ + is an experimental feature", + cfg_fn!(naked_functions))), + (sym::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::ffi_returns_twice, + "the `#[ffi_returns_twice]` attribute \ + is an experimental feature", + cfg_fn!(ffi_returns_twice))), + (sym::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated), + (sym::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::inline, Whitelisted, template!(Word, List: "always|never"), Ungated), + (sym::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", + /*opt*/ cfg = "...""#), Ungated), + (sym::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::no_builtins, Whitelisted, template!(Word), Ungated), + (sym::no_debug, Whitelisted, template!(Word), Gated( + Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), + sym::no_debug, + "the `#[no_debug]` attribute was an experimental feature that has been \ + deprecated due to lack of demand", + cfg_fn!(no_debug))), + ( + sym::omit_gdb_pretty_printer_section, + Whitelisted, + template!(Word), + Gated( + Stability::Unstable, + sym::omit_gdb_pretty_printer_section, + "the `#[omit_gdb_pretty_printer_section]` \ + attribute is just used for the Rust test \ + suite", + cfg_fn!(omit_gdb_pretty_printer_section) + ) + ), + (sym::may_dangle, + Normal, + template!(Word), + Gated(Stability::Unstable, + sym::dropck_eyepatch, + "`may_dangle` has unstable semantics and may be removed in the future", + cfg_fn!(dropck_eyepatch))), + (sym::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable, + sym::unwind_attributes, + "`#[unwind]` is experimental", + cfg_fn!(unwind_attributes))), + (sym::used, Whitelisted, template!(Word), Ungated), + + // used in resolve + (sym::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::prelude_import, + "`#[prelude_import]` is for use by rustc only", + cfg_fn!(prelude_import))), + + // FIXME: #14407 these are only looked at on-demand so we can't + // guarantee they'll have already been checked + ( + sym::rustc_deprecated, + Whitelisted, + template!(List: r#"since = "version", reason = "...""#), + Ungated + ), + (sym::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), + ( + sym::stable, + Whitelisted, + template!(List: r#"feature = "name", since = "version""#), + Ungated + ), + ( + sym::unstable, + Whitelisted, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), + Ungated + ), + (sym::deprecated, + Normal, + template!( + Word, + List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, + NameValueStr: "reason" + ), + Ungated + ), + + (sym::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable, + sym::unboxed_closures, + "unboxed_closures are still evolving", + cfg_fn!(unboxed_closures))), + + (sym::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated), + + (sym::proc_macro_attribute, Normal, template!(Word), Ungated), + (sym::proc_macro, Normal, template!(Word), Ungated), + + (sym::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "used internally by rustc", + cfg_fn!(rustc_attrs))), + + (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, + sym::allow_fail, + "allow_fail attribute is currently unstable", + cfg_fn!(allow_fail))), + + (sym::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "this is an internal attribute that will \ + never be stable", + cfg_fn!(rustc_attrs))), + + // whitelists "identity-like" conversion methods to suggest on type mismatch + (sym::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "this is an internal attribute that will \ + never be stable", + cfg_fn!(rustc_attrs))), + + ( + sym::rustc_args_required_const, + Whitelisted, + template!(List: "N"), + Gated(Stability::Unstable, sym::rustc_attrs, "never will be stable", + cfg_fn!(rustc_attrs)) + ), + // RFC 2070 + (sym::panic_handler, Normal, template!(Word), Ungated), + + (sym::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable, + sym::alloc_error_handler, + "`#[alloc_error_handler]` is an unstable feature", + cfg_fn!(alloc_error_handler))), + + // RFC 2412 + (sym::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, + sym::optimize_attribute, + "`#[optimize]` attribute is an unstable feature", + cfg_fn!(optimize_attribute))), + + // Crate level attributes + (sym::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated), + (sym::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), + (sym::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated), + (sym::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated), + (sym::no_start, CrateLevel, template!(Word), Ungated), + (sym::no_main, CrateLevel, template!(Word), Ungated), + (sym::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), + (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), + (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable, + sym::custom_test_frameworks, + "custom test frameworks are an unstable feature", + cfg_fn!(custom_test_frameworks))), +]; + +pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { + BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() +} + +pub fn is_builtin_attr_name(name: ast::Name) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() +} + +pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some() +} + +lazy_static! { + pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { + let mut map = FxHashMap::default(); + for attr in BUILTIN_ATTRIBUTES.iter() { + if map.insert(attr.0, attr).is_some() { + panic!("duplicate builtin attribute `{}`", attr.0); + } + } + map + }; +} -- cgit 1.4.1-3-g733a5 From 1c979ad55256d065a6d035a01910726a16644223 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Aug 2019 18:37:28 +0200 Subject: builtin_attrs.rs: simplify `cfg_fn`. --- src/libsyntax/feature_gate/builtin_attrs.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index 17e58df89e1..7cd295b1b2c 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -16,17 +16,16 @@ use syntax_pos::Span; use rustc_data_structures::fx::FxHashMap; use lazy_static::lazy_static; +type GateFn = fn(&Features) -> bool; + macro_rules! cfg_fn { - ($field: ident) => {{ - fn f(features: &Features) -> bool { - features.$field - } - f as fn(&Features) -> bool - }} + ($field: ident) => { + (|features| { features.$field }) as GateFn + } } -// cfg(...)'s that are feature gated -const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[ +/// `cfg(...)`'s that are feature gated. +const GATED_CFGS: &[(Symbol, Symbol, GateFn)] = &[ // (name in cfg, feature, function to check if the feature is enabled) (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), -- cgit 1.4.1-3-g733a5 From 0d19d1d7752bfed460bf7899171865441d6a2d87 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Aug 2019 19:37:04 +0200 Subject: builtin_attrs.rs: refactor `rustc_attrs` entries. --- src/libsyntax/feature_gate/builtin_attrs.rs | 342 +++++++++------------------- 1 file changed, 109 insertions(+), 233 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index 7cd295b1b2c..ad2e6a3feac 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -128,6 +128,21 @@ macro_rules! template { } }; } +macro_rules! rustc_attr { + (TEST, $gate:ident, $typ:expr, $tpl:expr $(,)?) => { + rustc_attr!( + $gate, $typ, $tpl, + concat!("the `#[", stringify!($gate), "]` attribute is just used for rustc unit tests \ + and will never be stable", + ), + ) + }; + ($gate:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { + (sym::$gate, $typ, $tpl, + Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs))) + }; +} + pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); /// Attributes that have a special meaning to rustc or rustdoc @@ -272,193 +287,78 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ attribute is an experimental \ feature", cfg_fn!(needs_panic_runtime))), - (sym::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_outlives]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_variance]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout, Normal, template!(List: "field1, field2, ..."), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout_scalar_valid_range_start]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout_scalar_valid_range_end]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_nonnull_optimization_guaranteed]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_regions]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_error]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", - /*opt*/ except = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dirty]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", - /*opt*/ except = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_clean]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ( - sym::rustc_partition_reused, - Whitelisted, + + rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), + rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), + rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), + rustc_attr!( + rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), + "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + rustc_attr!( + rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), + "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + rustc_attr!( + rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), + "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), + rustc_attr!(TEST, rustc_error, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dump_user_substs, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode")), + rustc_attr!(TEST, rustc_then_this_would_need, Whitelisted, template!(List: "DepNode")), + rustc_attr!( + TEST, rustc_dirty, Whitelisted, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), + ), + rustc_attr!( + TEST, rustc_clean, Whitelisted, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), + ), + rustc_attr!( + TEST, rustc_partition_reused, Whitelisted, template!(List: r#"cfg = "...", module = "...""#), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs) - ) ), - ( - sym::rustc_partition_codegened, - Whitelisted, + rustc_attr!( + TEST, rustc_partition_codegened, Whitelisted, template!(List: r#"cfg = "...", module = "...""#), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs), - ) ), - (sym::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...", - kind = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_mir]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ( - sym::rustc_inherit_overflow_checks, - Whitelisted, - template!(Word), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_inherit_overflow_checks]` \ - attribute is just used to control \ - overflow checking behavior of several \ - libcore functions that are inlined \ - across crates and will never be stable", - cfg_fn!(rustc_attrs), - ) + rustc_attr!( + TEST, rustc_expected_cgu_reuse, Whitelisted, + template!(List: r#"cfg = "...", module = "...", kind = "...""#), + ), + rustc_attr!(TEST, rustc_synthetic, Whitelisted, template!(Word)), + rustc_attr!( + rustc_symbol_name, Whitelisted, template!(Word), + "internal rustc attributes will never be stable", + ), + rustc_attr!( + rustc_def_path, Whitelisted, template!(Word), + "internal rustc attributes will never be stable", + ), + rustc_attr!(TEST, rustc_mir, Whitelisted, template!(List: "arg1, arg2, ...")), + rustc_attr!( + rustc_inherit_overflow_checks, Whitelisted, template!(Word), + "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ + overflow checking behavior of several libcore functions that are inlined \ + across crates and will never be stable", + ), + rustc_attr!(TEST, rustc_dump_program_clauses, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dump_env_program_clauses, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_object_lifetime_default, Whitelisted, template!(Word)), + rustc_attr!( + rustc_test_marker, Normal, template!(Word), + "the `#[rustc_test_marker]` attribute is used internally to track tests", + ), + rustc_attr!( + rustc_macro_transparency, Whitelisted, + template!(NameValueStr: "transparent|semitransparent|opaque"), + "used internally for testing macro hygiene", ), - - (sym::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dump_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dump_env_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dump_env_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_object_lifetime_default, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_object_lifetime_default]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_test_marker]` attribute \ - is used internally to track tests", - cfg_fn!(rustc_attrs))), - (sym::rustc_macro_transparency, Whitelisted, template!(NameValueStr: - "transparent|semitransparent|opaque"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "used internally for testing macro hygiene", - cfg_fn!(rustc_attrs))), (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, sym::compiler_builtins, "the `#[compiler_builtins]` attribute is used to \ @@ -501,35 +401,21 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ /*opt*/ attributes(name1, name2, ...)"), Ungated), - (sym::rustc_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_allocator_nounwind, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_builtin_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_promotable, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_allow_const_fn_ptr, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_dummy, Normal, template!(Word /* doesn't matter*/), Gated(Stability::Unstable, - sym::rustc_attrs, - "used by the test suite", - cfg_fn!(rustc_attrs))), + rustc_attr!(rustc_allocator, Whitelisted, template!(Word), "internal implementation detail"), + rustc_attr!( + rustc_allocator_nounwind, Whitelisted, template!(Word), + "internal implementation detail", + ), + rustc_attr!( + rustc_builtin_macro, Whitelisted, template!(Word), + "internal implementation detail" + ), + rustc_attr!(rustc_promotable, Whitelisted, template!(Word), "internal implementation detail"), + rustc_attr!( + rustc_allow_const_fn_ptr, Whitelisted, template!(Word), + "internal implementation detail", + ), + rustc_attr!(rustc_dummy, Normal, template!(Word /* doesn't matter*/), "used by the test suite"), // FIXME: #14408 whitelist docs since rustdoc looks at them ( @@ -639,35 +525,25 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ (sym::proc_macro_attribute, Normal, template!(Word), Ungated), (sym::proc_macro, Normal, template!(Word), Ungated), - (sym::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "used internally by rustc", - cfg_fn!(rustc_attrs))), + rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), "used internally by rustc"), (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, sym::allow_fail, "allow_fail attribute is currently unstable", cfg_fn!(allow_fail))), - (sym::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), - + rustc_attr!( + rustc_std_internal_symbol, Whitelisted, template!(Word), + "this is an internal attribute that will never be stable", + ), // whitelists "identity-like" conversion methods to suggest on type mismatch - (sym::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), - - ( - sym::rustc_args_required_const, - Whitelisted, - template!(List: "N"), - Gated(Stability::Unstable, sym::rustc_attrs, "never will be stable", - cfg_fn!(rustc_attrs)) + rustc_attr!( + rustc_conversion_suggestion, Whitelisted, template!(Word), + "this is an internal attribute that will never be stable", + ), + rustc_attr!( + rustc_args_required_const, Whitelisted, template!(List: "N"), + "this is an internal attribute that will never be stable", ), // RFC 2070 (sym::panic_handler, Normal, template!(Word), Ungated), -- cgit 1.4.1-3-g733a5 From 584388c4aac430fbf41114d94b9c6debfe191e62 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Aug 2019 20:40:50 +0200 Subject: builtin_attrs.rs: cleanup with `(un)gated!`. --- src/libsyntax/feature_gate/builtin_attrs.rs | 517 ++++++++++++---------------- 1 file changed, 229 insertions(+), 288 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index ad2e6a3feac..3188e92ed78 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -128,17 +128,32 @@ macro_rules! template { } }; } +macro_rules! ungated { + ($attr:ident, $typ:expr, $tpl:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Ungated) + }; +} + +macro_rules! gated { + ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate))) + }; + ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr))) + }; +} + macro_rules! rustc_attr { - (TEST, $gate:ident, $typ:expr, $tpl:expr $(,)?) => { + (TEST, $attr:ident, $typ:expr, $tpl:expr $(,)?) => { rustc_attr!( - $gate, $typ, $tpl, - concat!("the `#[", stringify!($gate), "]` attribute is just used for rustc unit tests \ + $attr, $typ, $tpl, + concat!("the `#[", stringify!($attr), "]` attribute is just used for rustc unit tests \ and will never be stable", ), ) }; - ($gate:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { - (sym::$gate, $typ, $tpl, + ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs))) }; } @@ -149,145 +164,106 @@ pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, Attribute pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Normal attributes - ( - sym::warn, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::allow, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated + ungated!(warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + + ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), + ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")), + ungated!(plugin_registrar, Normal, template!(Word)), + + ungated!(cfg, Normal, template!(List: "predicate")), + ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")), + ungated!(main, Normal, template!(Word)), + ungated!(start, Normal, template!(Word)), + ungated!(repr, Normal, template!(List: "C, packed, ...")), + ungated!(path, Normal, template!(NameValueStr: "file")), + ungated!(automatically_derived, Normal, template!(Word)), + ungated!(no_mangle, Whitelisted, template!(Word)), + ungated!(no_link, Normal, template!(Word)), + ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")), + ungated!( + should_panic, Normal, + template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), ), - ( - sym::forbid, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated + ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")), + ungated!(no_implicit_prelude, Normal, template!(Word)), + ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), + gated!( + link_args, Normal, template!(NameValueStr: "args"), + "the `link_args` attribute is experimental and not portable across platforms, \ + it is recommended to use `#[link(name = \"foo\")] instead", ), - ( - sym::deny, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - - (sym::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated), - (sym::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated), - (sym::plugin_registrar, Normal, template!(Word), Ungated), - - (sym::cfg, Normal, template!(List: "predicate"), Ungated), - (sym::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), - (sym::main, Normal, template!(Word), Ungated), - (sym::start, Normal, template!(Word), Ungated), - (sym::repr, Normal, template!(List: "C, packed, ..."), Ungated), - (sym::path, Normal, template!(NameValueStr: "file"), Ungated), - (sym::automatically_derived, Normal, template!(Word), Ungated), - (sym::no_mangle, Whitelisted, template!(Word), Ungated), - (sym::no_link, Normal, template!(Word), Ungated), - (sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated), - ( - sym::should_panic, - Normal, - template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), - Ungated - ), - (sym::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated), - (sym::no_implicit_prelude, Normal, template!(Word), Ungated), - (sym::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated), - (sym::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, - sym::link_args, - "the `link_args` attribute is experimental and not \ - portable across platforms, it is recommended to \ - use `#[link(name = \"foo\")] instead", - cfg_fn!(link_args))), - (sym::macro_escape, Normal, template!(Word), Ungated), + ungated!(macro_escape, Normal, template!(Word)), // RFC #1445. - (sym::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::structural_match, - "the semantics of constant patterns is \ - not yet settled", - cfg_fn!(structural_match))), + gated!( + structural_match, Whitelisted, template!(Word), + "the semantics of constant patterns is not yet settled", + ), // RFC #2008 - (sym::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::non_exhaustive, - "non exhaustive is an experimental feature", - cfg_fn!(non_exhaustive))), + gated!( + non_exhaustive, Whitelisted, template!(Word), + "non exhaustive is an experimental feature", + ), // RFC #1268 - (sym::marker, Normal, template!(Word), Gated(Stability::Unstable, - sym::marker_trait_attr, - "marker traits is an experimental feature", - cfg_fn!(marker_trait_attr))), - - (sym::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, - sym::plugin, - "compiler plugins are experimental \ - and possibly buggy", - cfg_fn!(plugin))), - - (sym::no_std, CrateLevel, template!(Word), Ungated), - (sym::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable, - sym::no_core, - "no_core is experimental", - cfg_fn!(no_core))), - (sym::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, - sym::lang_items, - "language items are subject to change", - cfg_fn!(lang_items))), - (sym::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), - Gated(Stability::Unstable, - sym::linkage, - "the `linkage` attribute is experimental \ - and not portable across platforms", - cfg_fn!(linkage))), - (sym::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::thread_local, - "`#[thread_local]` is an experimental feature, and does \ - not currently handle destructors", - cfg_fn!(thread_local))), - - (sym::rustc_on_unimplemented, Whitelisted, template!(List: - r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, - NameValueStr: "message"), - Gated(Stability::Unstable, - sym::on_unimplemented, - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature", - cfg_fn!(on_unimplemented))), - (sym::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), - Gated(Stability::Unstable, - sym::rustc_const_unstable, - "the `#[rustc_const_unstable]` attribute \ - is an internal feature", - cfg_fn!(rustc_const_unstable))), - (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::allocator_internals, - "the `#[default_lib_allocator]` \ - attribute is an experimental feature", - cfg_fn!(allocator_internals))), - (sym::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable, - sym::allocator_internals, - "the `#[needs_allocator]` \ - attribute is an experimental \ - feature", - cfg_fn!(allocator_internals))), - (sym::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::panic_runtime, - "the `#[panic_runtime]` attribute is \ - an experimental feature", - cfg_fn!(panic_runtime))), - (sym::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::needs_panic_runtime, - "the `#[needs_panic_runtime]` \ - attribute is an experimental \ - feature", - cfg_fn!(needs_panic_runtime))), + gated!( + marker, Normal, template!(Word), marker_trait_attr, + "marker traits is an experimental feature", + ), + + gated!( + plugin, CrateLevel, template!(List: "name|name(args)"), + "compiler plugins are experimental and possibly buggy", + ), + + ungated!(no_std, CrateLevel, template!(Word)), + gated!(no_core, CrateLevel, template!(Word), "no_core is experimental"), + gated!( + lang, Normal, template!(NameValueStr: "name"), lang_items, + "language items are subject to change", + ), + gated!( + linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), + "the `linkage` attribute is experimental and not portable across platforms", + ), + gated!( + thread_local, Whitelisted, template!(Word), + "`#[thread_local]` is an experimental feature, and does not currently handle destructors", + ), + gated!( + rustc_on_unimplemented, Whitelisted, + template!( + List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, + NameValueStr: "message" + ), + on_unimplemented, + "the `#[rustc_on_unimplemented]` attribute is an experimental feature", + ), + gated!( + rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), + "the `#[rustc_const_unstable]` attribute is an internal feature", + ), + gated!( + default_lib_allocator, Whitelisted, template!(Word), allocator_internals, + "the `#[default_lib_allocator]` attribute is an experimental feature", + ), + gated!( + needs_allocator, Normal, template!(Word), allocator_internals, + "the `#[needs_allocator]` attribute is an experimental feature", + ), + gated!( + panic_runtime, Whitelisted, template!(Word), + "the `#[panic_runtime]` attribute is an experimental feature", + ), + gated!( + needs_panic_runtime, Whitelisted, template!(Word), + "the `#[needs_panic_runtime]` attribute is an experimental feature", + ), rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), @@ -359,47 +335,38 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(NameValueStr: "transparent|semitransparent|opaque"), "used internally for testing macro hygiene", ), - (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::compiler_builtins, - "the `#[compiler_builtins]` attribute is used to \ - identify the `compiler_builtins` crate which \ - contains compiler-rt intrinsics and will never be \ - stable", - cfg_fn!(compiler_builtins))), - (sym::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::sanitizer_runtime, - "the `#[sanitizer_runtime]` attribute is used to \ - identify crates that contain the runtime of a \ - sanitizer and will never be stable", - cfg_fn!(sanitizer_runtime))), - (sym::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::profiler_runtime, - "the `#[profiler_runtime]` attribute is used to \ - identify the `profiler_builtins` crate which \ - contains the profiler runtime and will never be \ - stable", - cfg_fn!(profiler_runtime))), - - (sym::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), - Gated(Stability::Unstable, - sym::allow_internal_unstable, - EXPLAIN_ALLOW_INTERNAL_UNSTABLE, - cfg_fn!(allow_internal_unstable))), - - (sym::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable, - sym::allow_internal_unsafe, - EXPLAIN_ALLOW_INTERNAL_UNSAFE, - cfg_fn!(allow_internal_unsafe))), - - (sym::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::fundamental, - "the `#[fundamental]` attribute \ - is an experimental feature", - cfg_fn!(fundamental))), - - (sym::proc_macro_derive, Normal, template!(List: "TraitName, \ - /*opt*/ attributes(name1, name2, ...)"), - Ungated), + + gated!( + compiler_builtins, Whitelisted, template!(Word), + "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ + which contains compiler-rt intrinsics and will never be stable", + ), + gated!( + sanitizer_runtime, Whitelisted, template!(Word), + "the `#[sanitizer_runtime]` attribute is used to identify crates that contain the runtime \ + of a sanitizer and will never be stable", + ), + gated!( + profiler_runtime, Whitelisted, template!(Word), + "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \ + which contains the profiler runtime and will never be stable", + ), + + gated!( + allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + EXPLAIN_ALLOW_INTERNAL_UNSTABLE, + ), + gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE), + + gated!( + fundamental, Whitelisted, template!(Word), + "the `#[fundamental]` attribute is an experimental feature", + ), + + ungated!( + proc_macro_derive, Normal, + template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), + ), rustc_attr!(rustc_allocator, Whitelisted, template!(Word), "internal implementation detail"), rustc_attr!( @@ -418,119 +385,93 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_dummy, Normal, template!(Word /* doesn't matter*/), "used by the test suite"), // FIXME: #14408 whitelist docs since rustdoc looks at them + ungated!(doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string")), + + // FIXME: #14406 these are processed in codegen, which happens after the lint pass + + ungated!(cold, Whitelisted, template!(Word)), + gated!( + naked, Whitelisted, template!(Word), naked_functions, + "the `#[naked]` attribute is an experimental feature", + ), + gated!( + ffi_returns_twice, Whitelisted, template!(Word), + "the `#[ffi_returns_twice]` attribute is an experimental feature", + ), + ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)), + ungated!(export_name, Whitelisted, template!(NameValueStr: "name")), + ungated!(inline, Whitelisted, template!(Word, List: "always|never")), + ungated!( + link, Whitelisted, + template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...""#), + ), + ungated!(link_name, Whitelisted, template!(NameValueStr: "name")), + ungated!(link_section, Whitelisted, template!(NameValueStr: "name")), + ungated!(no_builtins, Whitelisted, template!(Word)), ( - sym::doc, - Whitelisted, - template!(List: "hidden|inline|...", NameValueStr: "string"), - Ungated - ), - - // FIXME: #14406 these are processed in codegen, which happens after the - // lint pass - (sym::cold, Whitelisted, template!(Word), Ungated), - (sym::naked, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::naked_functions, - "the `#[naked]` attribute \ - is an experimental feature", - cfg_fn!(naked_functions))), - (sym::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::ffi_returns_twice, - "the `#[ffi_returns_twice]` attribute \ - is an experimental feature", - cfg_fn!(ffi_returns_twice))), - (sym::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated), - (sym::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::inline, Whitelisted, template!(Word, List: "always|never"), Ungated), - (sym::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...""#), Ungated), - (sym::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::no_builtins, Whitelisted, template!(Word), Ungated), - (sym::no_debug, Whitelisted, template!(Word), Gated( - Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), - sym::no_debug, - "the `#[no_debug]` attribute was an experimental feature that has been \ - deprecated due to lack of demand", - cfg_fn!(no_debug))), - ( - sym::omit_gdb_pretty_printer_section, - Whitelisted, - template!(Word), + sym::no_debug, Whitelisted, template!(Word), Gated( - Stability::Unstable, - sym::omit_gdb_pretty_printer_section, - "the `#[omit_gdb_pretty_printer_section]` \ - attribute is just used for the Rust test \ - suite", - cfg_fn!(omit_gdb_pretty_printer_section) + Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), + sym::no_debug, + "the `#[no_debug]` attribute was an experimental feature that has been \ + deprecated due to lack of demand", + cfg_fn!(no_debug) ) ), - (sym::may_dangle, - Normal, - template!(Word), - Gated(Stability::Unstable, - sym::dropck_eyepatch, + gated!( + omit_gdb_pretty_printer_section, Whitelisted, template!(Word), + "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", + ), + gated!( + may_dangle, Normal, template!(Word), dropck_eyepatch, "`may_dangle` has unstable semantics and may be removed in the future", - cfg_fn!(dropck_eyepatch))), - (sym::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable, - sym::unwind_attributes, - "`#[unwind]` is experimental", - cfg_fn!(unwind_attributes))), - (sym::used, Whitelisted, template!(Word), Ungated), - - // used in resolve - (sym::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::prelude_import, - "`#[prelude_import]` is for use by rustc only", - cfg_fn!(prelude_import))), + ), + gated!( + unwind, Whitelisted, template!(List: "allowed|aborts"), unwind_attributes, + "`#[unwind]` is experimental", + ), + ungated!(used, Whitelisted, template!(Word)), + + // Used in resolve: + gated!( + prelude_import, Whitelisted, template!(Word), + "`#[prelude_import]` is for use by rustc only", + ), // FIXME: #14407 these are only looked at on-demand so we can't // guarantee they'll have already been checked - ( - sym::rustc_deprecated, - Whitelisted, - template!(List: r#"since = "version", reason = "...""#), - Ungated - ), - (sym::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), - ( - sym::stable, - Whitelisted, - template!(List: r#"feature = "name", since = "version""#), - Ungated + ungated!( + rustc_deprecated, Whitelisted, + template!(List: r#"since = "version", reason = "...""#) ), - ( - sym::unstable, - Whitelisted, + ungated!(must_use, Whitelisted, template!(Word, NameValueStr: "reason")), + ungated!(stable, Whitelisted, template!(List: r#"feature = "name", since = "version""#)), + ungated!( + unstable, Whitelisted, template!(List: r#"feature = "name", reason = "...", issue = "N""#), - Ungated ), - (sym::deprecated, - Normal, + ungated!( + deprecated, Normal, template!( Word, List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, NameValueStr: "reason" ), - Ungated ), - (sym::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable, - sym::unboxed_closures, - "unboxed_closures are still evolving", - cfg_fn!(unboxed_closures))), + gated!( + rustc_paren_sugar, Normal, template!(Word), unboxed_closures, + "unboxed_closures are still evolving", + ), - (sym::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated), + ungated!(windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console")), - (sym::proc_macro_attribute, Normal, template!(Word), Ungated), - (sym::proc_macro, Normal, template!(Word), Ungated), + ungated!(proc_macro_attribute, Normal, template!(Word)), + ungated!(proc_macro, Normal, template!(Word)), rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), "used internally by rustc"), - (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, - sym::allow_fail, - "allow_fail attribute is currently unstable", - cfg_fn!(allow_fail))), + gated!(allow_fail, Normal, template!(Word), "allow_fail attribute is currently unstable"), rustc_attr!( rustc_std_internal_symbol, Whitelisted, template!(Word), @@ -545,33 +486,33 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_args_required_const, Whitelisted, template!(List: "N"), "this is an internal attribute that will never be stable", ), - // RFC 2070 - (sym::panic_handler, Normal, template!(Word), Ungated), - (sym::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable, - sym::alloc_error_handler, - "`#[alloc_error_handler]` is an unstable feature", - cfg_fn!(alloc_error_handler))), + // RFC 2070 + ungated!(panic_handler, Normal, template!(Word)), + gated!( + alloc_error_handler, Normal, template!(Word), + "`#[alloc_error_handler]` is an unstable feature", + ), // RFC 2412 - (sym::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, - sym::optimize_attribute, - "`#[optimize]` attribute is an unstable feature", - cfg_fn!(optimize_attribute))), + gated!( + optimize, Whitelisted, template!(List: "size|speed"), optimize_attribute, + "`#[optimize]` attribute is an unstable feature", + ), // Crate level attributes - (sym::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated), - (sym::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), - (sym::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated), - (sym::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated), - (sym::no_start, CrateLevel, template!(Word), Ungated), - (sym::no_main, CrateLevel, template!(Word), Ungated), - (sym::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable, - sym::custom_test_frameworks, - "custom test frameworks are an unstable feature", - cfg_fn!(custom_test_frameworks))), + ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")), + ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")), + ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")), + ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")), + ungated!(no_start, CrateLevel, template!(Word)), + ungated!(no_main, CrateLevel, template!(Word)), + ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), + ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), + gated!( + test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks, + "custom test frameworks are an unstable feature", + ), ]; pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { -- cgit 1.4.1-3-g733a5 From d286fe0b8d33175cf89c1bc92717bc3bff857420 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Aug 2019 23:30:59 +0200 Subject: builtin_attrs.rs: organize! --- src/libsyntax/feature_gate/builtin_attrs.rs | 500 ++++++++++++++-------------- 1 file changed, 259 insertions(+), 241 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index 3188e92ed78..293e63c4c16 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -158,184 +158,215 @@ macro_rules! rustc_attr { }; } +macro_rules! experimental { + ($attr:ident) => { + concat!("the `#[", stringify!($attr), "]` attribute is an experimental feature") + } +} + +const IMPL_DETAIL: &str = "internal implementation detail"; +const INTERAL_UNSTABLE: &str = "this is an internal attribute that will never be stable"; + pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); /// Attributes that have a special meaning to rustc or rustdoc pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ - // Normal attributes + // ========================================================================== + // Stable attributes: + // ========================================================================== + + // Condtional compilation: + ungated!(cfg, Normal, template!(List: "predicate")), + ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")), + // Testing: + ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")), + ungated!( + should_panic, Normal, + template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), + ), + // FIXME(Centril): This can be used on stable but shouldn't. + ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), + + // Macros: + ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")), + ungated!(automatically_derived, Normal, template!(Word)), + ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), + ungated!(macro_escape, Normal, template!(Word)), // Deprecated synonym for `macro_use`. + ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")), + ungated!(proc_macro, Normal, template!(Word)), + ungated!( + proc_macro_derive, Normal, + template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), + ), + ungated!(proc_macro_attribute, Normal, template!(Word)), + + // Lints: ungated!(warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(must_use, Whitelisted, template!(Word, NameValueStr: "reason")), + ungated!( + deprecated, Normal, + template!( + Word, + List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, + NameValueStr: "reason" + ), + ), - ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), - ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")), - ungated!(plugin_registrar, Normal, template!(Word)), + // Crate properties: + ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")), + ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")), + ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")), - ungated!(cfg, Normal, template!(List: "predicate")), - ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")), + // ABI, linking, symbols, and FFI + ungated!( + link, Whitelisted, + template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...""#), + ), + ungated!(link_name, Whitelisted, template!(NameValueStr: "name")), + ungated!(no_link, Normal, template!(Word)), + ungated!(repr, Normal, template!(List: "C, packed, ...")), + ungated!(export_name, Whitelisted, template!(NameValueStr: "name")), + ungated!(link_section, Whitelisted, template!(NameValueStr: "name")), + ungated!(no_mangle, Whitelisted, template!(Word)), + ungated!(used, Whitelisted, template!(Word)), + + // Limits: + ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), + ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), + + // Entry point: ungated!(main, Normal, template!(Word)), ungated!(start, Normal, template!(Word)), - ungated!(repr, Normal, template!(List: "C, packed, ...")), + ungated!(no_start, CrateLevel, template!(Word)), + ungated!(no_main, CrateLevel, template!(Word)), + + // Modules, prelude, and resolution: ungated!(path, Normal, template!(NameValueStr: "file")), - ungated!(automatically_derived, Normal, template!(Word)), - ungated!(no_mangle, Whitelisted, template!(Word)), - ungated!(no_link, Normal, template!(Word)), - ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")), - ungated!( - should_panic, Normal, - template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), - ), - ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")), + ungated!(no_std, CrateLevel, template!(Word)), ungated!(no_implicit_prelude, Normal, template!(Word)), - ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), + + // Runtime + ungated!(windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console")), + ungated!(panic_handler, Normal, template!(Word)), // RFC 2070 + + // Code generation: + ungated!(inline, Whitelisted, template!(Word, List: "always|never")), + ungated!(cold, Whitelisted, template!(Word)), + ungated!(no_builtins, Whitelisted, template!(Word)), + ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)), + + // FIXME: #14408 whitelist docs since rustdoc looks at them + ungated!(doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string")), + + // ========================================================================== + // Unstable attributes: + // ========================================================================== + + // Linking: + gated!(naked, Whitelisted, template!(Word), naked_functions, experimental!(naked)), gated!( link_args, Normal, template!(NameValueStr: "args"), "the `link_args` attribute is experimental and not portable across platforms, \ it is recommended to use `#[link(name = \"foo\")] instead", ), - ungated!(macro_escape, Normal, template!(Word)), - // RFC #1445. + // Plugins: + ungated!(plugin_registrar, Normal, template!(Word)), gated!( - structural_match, Whitelisted, template!(Word), - "the semantics of constant patterns is not yet settled", + plugin, CrateLevel, template!(List: "name|name(args)"), + "compiler plugins are experimental and possibly buggy", ), - // RFC #2008 + // Testing: + gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)), gated!( - non_exhaustive, Whitelisted, template!(Word), - "non exhaustive is an experimental feature", + test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks, + "custom test frameworks are an unstable feature", ), + // RFC #2008 + gated!(non_exhaustive, Whitelisted, template!(Word), experimental!(non_exhaustive)), // RFC #1268 + gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), gated!( - marker, Normal, template!(Word), marker_trait_attr, - "marker traits is an experimental feature", + thread_local, Whitelisted, template!(Word), + "`#[thread_local]` is an experimental feature, and does not currently handle destructors", ), - + gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)), + // RFC 2412 gated!( - plugin, CrateLevel, template!(List: "name|name(args)"), - "compiler plugins are experimental and possibly buggy", + optimize, Whitelisted, template!(List: "size|speed"), optimize_attribute, + experimental!(optimize), ), - ungated!(no_std, CrateLevel, template!(Word)), - gated!(no_core, CrateLevel, template!(Word), "no_core is experimental"), - gated!( - lang, Normal, template!(NameValueStr: "name"), lang_items, - "language items are subject to change", + gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)), + + // ========================================================================== + // Internal attributes: Stability, deprecation, and unsafe: + // ========================================================================== + + ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")), + // FIXME: #14407 these are only looked at on-demand so we can't + // guarantee they'll have already been checked + ungated!( + rustc_deprecated, Whitelisted, + template!(List: r#"since = "version", reason = "...""#) + ), + ungated!(stable, Whitelisted, template!(List: r#"feature = "name", since = "version""#)), + ungated!( + unstable, Whitelisted, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), ), gated!( - linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), - "the `linkage` attribute is experimental and not portable across platforms", + rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), + "the `#[rustc_const_unstable]` attribute is an internal feature", ), gated!( - thread_local, Whitelisted, template!(Word), - "`#[thread_local]` is an experimental feature, and does not currently handle destructors", + allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + EXPLAIN_ALLOW_INTERNAL_UNSTABLE, ), + gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE), + + // ========================================================================== + // Internal attributes: Type system related: + // ========================================================================== + gated!(fundamental, Whitelisted, template!(Word), experimental!(fundamental)), gated!( - rustc_on_unimplemented, Whitelisted, - template!( - List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, - NameValueStr: "message" - ), - on_unimplemented, - "the `#[rustc_on_unimplemented]` attribute is an experimental feature", + // RFC #1445. + structural_match, Whitelisted, template!(Word), + "the semantics of constant patterns is not yet settled", ), gated!( - rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), - "the `#[rustc_const_unstable]` attribute is an internal feature", + may_dangle, Normal, template!(Word), dropck_eyepatch, + "`may_dangle` has unstable semantics and may be removed in the future", ), + + // ========================================================================== + // Internal attributes: Runtime related: + // ========================================================================== + + rustc_attr!(rustc_allocator, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_allocator_nounwind, Whitelisted, template!(Word), IMPL_DETAIL), + gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)), gated!( default_lib_allocator, Whitelisted, template!(Word), allocator_internals, - "the `#[default_lib_allocator]` attribute is an experimental feature", + experimental!(default_lib_allocator), ), gated!( needs_allocator, Normal, template!(Word), allocator_internals, - "the `#[needs_allocator]` attribute is an experimental feature", + experimental!(needs_allocator), ), + gated!(panic_runtime, Whitelisted, template!(Word), experimental!(panic_runtime)), + gated!(needs_panic_runtime, Whitelisted, template!(Word), experimental!(needs_panic_runtime)), gated!( - panic_runtime, Whitelisted, template!(Word), - "the `#[panic_runtime]` attribute is an experimental feature", - ), - gated!( - needs_panic_runtime, Whitelisted, template!(Word), - "the `#[needs_panic_runtime]` attribute is an experimental feature", - ), - rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), - rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), - rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), - rustc_attr!( - rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), - "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ - niche optimizations in libcore and will never be stable", - ), - rustc_attr!( - rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), - "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ - niche optimizations in libcore and will never be stable", - ), - rustc_attr!( - rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), - "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ - niche optimizations in libcore and will never be stable", - ), - rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), - rustc_attr!(TEST, rustc_error, Whitelisted, template!(Word)), - rustc_attr!(TEST, rustc_dump_user_substs, Whitelisted, template!(Word)), - rustc_attr!(TEST, rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode")), - rustc_attr!(TEST, rustc_then_this_would_need, Whitelisted, template!(List: "DepNode")), - rustc_attr!( - TEST, rustc_dirty, Whitelisted, - template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), - ), - rustc_attr!( - TEST, rustc_clean, Whitelisted, - template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), - ), - rustc_attr!( - TEST, rustc_partition_reused, Whitelisted, - template!(List: r#"cfg = "...", module = "...""#), - ), - rustc_attr!( - TEST, rustc_partition_codegened, Whitelisted, - template!(List: r#"cfg = "...", module = "...""#), - ), - rustc_attr!( - TEST, rustc_expected_cgu_reuse, Whitelisted, - template!(List: r#"cfg = "...", module = "...", kind = "...""#), - ), - rustc_attr!(TEST, rustc_synthetic, Whitelisted, template!(Word)), - rustc_attr!( - rustc_symbol_name, Whitelisted, template!(Word), - "internal rustc attributes will never be stable", - ), - rustc_attr!( - rustc_def_path, Whitelisted, template!(Word), - "internal rustc attributes will never be stable", - ), - rustc_attr!(TEST, rustc_mir, Whitelisted, template!(List: "arg1, arg2, ...")), - rustc_attr!( - rustc_inherit_overflow_checks, Whitelisted, template!(Word), - "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ - overflow checking behavior of several libcore functions that are inlined \ - across crates and will never be stable", - ), - rustc_attr!(TEST, rustc_dump_program_clauses, Whitelisted, template!(Word)), - rustc_attr!(TEST, rustc_dump_env_program_clauses, Whitelisted, template!(Word)), - rustc_attr!(TEST, rustc_object_lifetime_default, Whitelisted, template!(Word)), - rustc_attr!( - rustc_test_marker, Normal, template!(Word), - "the `#[rustc_test_marker]` attribute is used internally to track tests", - ), - rustc_attr!( - rustc_macro_transparency, Whitelisted, - template!(NameValueStr: "transparent|semitransparent|opaque"), - "used internally for testing macro hygiene", + unwind, Whitelisted, template!(List: "allowed|aborts"), unwind_attributes, + experimental!(unwind), ), - gated!( compiler_builtins, Whitelisted, template!(Word), "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ @@ -352,62 +383,80 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ which contains the profiler runtime and will never be stable", ), + // ========================================================================== + // Internal attributes, Linkage: + // ========================================================================== + gated!( - allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), - EXPLAIN_ALLOW_INTERNAL_UNSTABLE, + linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), + "the `linkage` attribute is experimental and not portable across platforms", ), - gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE), + rustc_attr!(rustc_std_internal_symbol, Whitelisted, template!(Word), INTERAL_UNSTABLE), - gated!( - fundamental, Whitelisted, template!(Word), - "the `#[fundamental]` attribute is an experimental feature", + // ========================================================================== + // Internal attributes, Macro related: + // ========================================================================== + + rustc_attr!(rustc_builtin_macro, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERAL_UNSTABLE), + rustc_attr!( + rustc_macro_transparency, Whitelisted, + template!(NameValueStr: "transparent|semitransparent|opaque"), + "used internally for testing macro hygiene", ), - ungated!( - proc_macro_derive, Normal, - template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), + // ========================================================================== + // Internal attributes, Diagnostics related: + // ========================================================================== + + gated!( + rustc_on_unimplemented, Whitelisted, + template!( + List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, + NameValueStr: "message" + ), + on_unimplemented, + experimental!(rustc_on_unimplemented), ), + // Whitelists "identity-like" conversion methods to suggest on type mismatch. + rustc_attr!(rustc_conversion_suggestion, Whitelisted, template!(Word), INTERAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Const related: + // ========================================================================== + + rustc_attr!(rustc_promotable, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_allow_const_fn_ptr, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_args_required_const, Whitelisted, template!(List: "N"), INTERAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Layout related: + // ========================================================================== - rustc_attr!(rustc_allocator, Whitelisted, template!(Word), "internal implementation detail"), rustc_attr!( - rustc_allocator_nounwind, Whitelisted, template!(Word), - "internal implementation detail", + rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), + "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", ), rustc_attr!( - rustc_builtin_macro, Whitelisted, template!(Word), - "internal implementation detail" + rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), + "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", ), - rustc_attr!(rustc_promotable, Whitelisted, template!(Word), "internal implementation detail"), rustc_attr!( - rustc_allow_const_fn_ptr, Whitelisted, template!(Word), - "internal implementation detail", + rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), + "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", ), - rustc_attr!(rustc_dummy, Normal, template!(Word /* doesn't matter*/), "used by the test suite"), - // FIXME: #14408 whitelist docs since rustdoc looks at them - ungated!(doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string")), - - // FIXME: #14406 these are processed in codegen, which happens after the lint pass + // ========================================================================== + // Internal attributes, Misc: + // ========================================================================== - ungated!(cold, Whitelisted, template!(Word)), gated!( - naked, Whitelisted, template!(Word), naked_functions, - "the `#[naked]` attribute is an experimental feature", - ), - gated!( - ffi_returns_twice, Whitelisted, template!(Word), - "the `#[ffi_returns_twice]` attribute is an experimental feature", - ), - ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)), - ungated!(export_name, Whitelisted, template!(NameValueStr: "name")), - ungated!(inline, Whitelisted, template!(Word, List: "always|never")), - ungated!( - link, Whitelisted, - template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...""#), + lang, Normal, template!(NameValueStr: "name"), lang_items, + "language items are subject to change", ), - ungated!(link_name, Whitelisted, template!(NameValueStr: "name")), - ungated!(link_section, Whitelisted, template!(NameValueStr: "name")), - ungated!(no_builtins, Whitelisted, template!(Word)), ( sym::no_debug, Whitelisted, template!(Word), Gated( @@ -419,99 +468,68 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ) ), gated!( - omit_gdb_pretty_printer_section, Whitelisted, template!(Word), - "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", - ), - gated!( - may_dangle, Normal, template!(Word), dropck_eyepatch, - "`may_dangle` has unstable semantics and may be removed in the future", - ), - gated!( - unwind, Whitelisted, template!(List: "allowed|aborts"), unwind_attributes, - "`#[unwind]` is experimental", - ), - ungated!(used, Whitelisted, template!(Word)), - - // Used in resolve: - gated!( + // Used in resolve: prelude_import, Whitelisted, template!(Word), "`#[prelude_import]` is for use by rustc only", ), - - // FIXME: #14407 these are only looked at on-demand so we can't - // guarantee they'll have already been checked - ungated!( - rustc_deprecated, Whitelisted, - template!(List: r#"since = "version", reason = "...""#) - ), - ungated!(must_use, Whitelisted, template!(Word, NameValueStr: "reason")), - ungated!(stable, Whitelisted, template!(List: r#"feature = "name", since = "version""#)), - ungated!( - unstable, Whitelisted, - template!(List: r#"feature = "name", reason = "...", issue = "N""#), - ), - ungated!( - deprecated, Normal, - template!( - Word, - List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, - NameValueStr: "reason" - ), - ), - gated!( rustc_paren_sugar, Normal, template!(Word), unboxed_closures, "unboxed_closures are still evolving", ), + rustc_attr!( + rustc_inherit_overflow_checks, Whitelisted, template!(Word), + "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ + overflow checking behavior of several libcore functions that are inlined \ + across crates and will never be stable", + ), + rustc_attr!( + rustc_test_marker, Normal, template!(Word), + "the `#[rustc_test_marker]` attribute is used internally to track tests", + ), - ungated!(windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console")), - - ungated!(proc_macro_attribute, Normal, template!(Word)), - ungated!(proc_macro, Normal, template!(Word)), - - rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), "used internally by rustc"), - - gated!(allow_fail, Normal, template!(Word), "allow_fail attribute is currently unstable"), + // ========================================================================== + // Internal attributes, Testing: + // ========================================================================== + rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), + rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), + rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), + rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), + rustc_attr!(TEST, rustc_error, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dump_user_substs, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode")), + rustc_attr!(TEST, rustc_then_this_would_need, Whitelisted, template!(List: "DepNode")), rustc_attr!( - rustc_std_internal_symbol, Whitelisted, template!(Word), - "this is an internal attribute that will never be stable", + TEST, rustc_dirty, Whitelisted, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), ), - // whitelists "identity-like" conversion methods to suggest on type mismatch rustc_attr!( - rustc_conversion_suggestion, Whitelisted, template!(Word), - "this is an internal attribute that will never be stable", + TEST, rustc_clean, Whitelisted, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), ), rustc_attr!( - rustc_args_required_const, Whitelisted, template!(List: "N"), - "this is an internal attribute that will never be stable", + TEST, rustc_partition_reused, Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), ), - - // RFC 2070 - ungated!(panic_handler, Normal, template!(Word)), - gated!( - alloc_error_handler, Normal, template!(Word), - "`#[alloc_error_handler]` is an unstable feature", + rustc_attr!( + TEST, rustc_partition_codegened, Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), ), - - // RFC 2412 - gated!( - optimize, Whitelisted, template!(List: "size|speed"), optimize_attribute, - "`#[optimize]` attribute is an unstable feature", + rustc_attr!( + TEST, rustc_expected_cgu_reuse, Whitelisted, + template!(List: r#"cfg = "...", module = "...", kind = "...""#), ), - - // Crate level attributes - ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")), - ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")), - ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")), - ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")), - ungated!(no_start, CrateLevel, template!(Word)), - ungated!(no_main, CrateLevel, template!(Word)), - ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), - ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), + rustc_attr!(TEST, rustc_synthetic, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_symbol_name, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_def_path, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_mir, Whitelisted, template!(List: "arg1, arg2, ...")), + rustc_attr!(TEST, rustc_dump_program_clauses, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dump_env_program_clauses, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_object_lifetime_default, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)), gated!( - test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks, - "custom test frameworks are an unstable feature", + omit_gdb_pretty_printer_section, Whitelisted, template!(Word), + "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", ), ]; -- cgit 1.4.1-3-g733a5 From e5aa2dd1ff73e3fc0a17a68938ffafe2d4ed0e8c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Aug 2019 23:35:03 +0200 Subject: builtin_attrs.rs: retain FIXMEs. --- src/libsyntax/feature_gate/builtin_attrs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index 293e63c4c16..9b347711fdd 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -191,6 +191,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Macros: ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")), ungated!(automatically_derived, Normal, template!(Word)), + // FIXME(#14407) ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), ungated!(macro_escape, Normal, template!(Word)), // Deprecated synonym for `macro_use`. ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")), @@ -207,6 +208,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(must_use, Whitelisted, template!(Word, NameValueStr: "reason")), + // FIXME(#14407) ungated!( deprecated, Normal, template!( @@ -310,13 +312,15 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")), - // FIXME: #14407 these are only looked at on-demand so we can't - // guarantee they'll have already been checked + // FIXME(#14407) -- only looked at on-demand so we can't + // guarantee they'll have already been checked. ungated!( rustc_deprecated, Whitelisted, template!(List: r#"since = "version", reason = "...""#) ), + // FIXME(#14407) ungated!(stable, Whitelisted, template!(List: r#"feature = "name", since = "version""#)), + // FIXME(#14407) ungated!( unstable, Whitelisted, template!(List: r#"feature = "name", reason = "...", issue = "N""#), -- cgit 1.4.1-3-g733a5 From 87eafd6c1b844f4258a2bbd7563c16609c4606e6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Aug 2019 23:48:08 +0200 Subject: syntax: extract `check.rs`. --- src/libsyntax/feature_gate.rs | 958 +--------------------------- src/libsyntax/feature_gate/builtin_attrs.rs | 4 +- src/libsyntax/feature_gate/check.rs | 951 +++++++++++++++++++++++++++ 3 files changed, 960 insertions(+), 953 deletions(-) create mode 100644 src/libsyntax/feature_gate/check.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0e04d4c6c23..97793bca1f5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -13,963 +13,19 @@ //! becomes stable. mod accepted; -use accepted::ACCEPTED_FEATURES; mod removed; -use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; mod active; -use active::{ACTIVE_FEATURES}; -pub use active::{Features, INCOMPLETE_FEATURES}; mod builtin_attrs; +mod check; + +pub use active::{Features, INCOMPLETE_FEATURES}; pub use builtin_attrs::{ AttributeGate, AttributeType, GatedCfg, BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, deprecated_attributes, is_builtin_attr, is_builtin_attr_name, }; - -use crate::ast::{ - self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, - PatKind, RangeEnd, +pub use check::{ + check_attribute, check_crate, get_features, feature_err, emit_feature_err, + Stability, GateIssue, UnstableFeatures, + EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION, }; -use crate::attr::{self, check_builtin_attribute}; -use crate::source_map::Spanned; -use crate::edition::{ALL_EDITIONS, Edition}; -use crate::visit::{self, FnKind, Visitor}; -use crate::parse::{token, ParseSess}; -use crate::parse::parser::Parser; -use crate::symbol::{Symbol, sym}; -use crate::tokenstream::TokenTree; - -use errors::{Applicability, DiagnosticBuilder, Handler}; -use rustc_data_structures::fx::FxHashMap; -use rustc_target::spec::abi::Abi; -use syntax_pos::{Span, DUMMY_SP, MultiSpan}; -use log::debug; - -use std::env; - -#[derive(Copy, Clone, Debug)] -pub enum Stability { - Unstable, - // First argument is tracking issue link; second argument is an optional - // help message, which defaults to "remove this attribute" - Deprecated(&'static str, Option<&'static str>), -} - -struct Context<'a> { - features: &'a Features, - parse_sess: &'a ParseSess, - plugin_attributes: &'a [(Symbol, AttributeType)], -} - -macro_rules! gate_feature_fn { - ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ - let (cx, has_feature, span, - name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level); - let has_feature: bool = has_feature(&$cx.features); - debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !span.allows_unstable($name) { - leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level) - .emit(); - } - }} -} - -macro_rules! gate_feature { - ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - sym::$feature, $explain, GateStrength::Hard) - }; - ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - sym::$feature, $explain, $level) - }; -} - -impl<'a> Context<'a> { - fn check_attribute( - &self, - attr: &ast::Attribute, - attr_info: Option<&BuiltinAttribute>, - is_macro: bool - ) { - debug!("check_attribute(attr = {:?})", attr); - if let Some(&(name, ty, _template, ref gateage)) = attr_info { - if let AttributeGate::Gated(_, name, desc, ref has_feature) = *gateage { - if !attr.span.allows_unstable(name) { - gate_feature_fn!( - self, has_feature, attr.span, name, desc, GateStrength::Hard - ); - } - } else if name == sym::doc { - if let Some(content) = attr.meta_item_list() { - if content.iter().any(|c| c.check_name(sym::include)) { - gate_feature!(self, external_doc, attr.span, - "`#[doc(include = \"...\")]` is experimental" - ); - } - } - } - debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); - return; - } else { - for segment in &attr.path.segments { - if segment.ident.as_str().starts_with("rustc") { - let msg = "attributes starting with `rustc` are \ - reserved for use by the `rustc` compiler"; - gate_feature!(self, rustc_attrs, segment.ident.span, msg); - } - } - } - for &(n, ty) in self.plugin_attributes { - if attr.path == n { - // Plugins can't gate attributes, so we don't check for it - // unlike the code above; we only use this loop to - // short-circuit to avoid the checks below. - debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty); - return; - } - } - if !is_macro && !attr::is_known(attr) { - // Only run the custom attribute lint during regular feature gate - // checking. Macro gating runs before the plugin attributes are - // registered, so we skip this in that case. - let msg = format!("the attribute `{}` is currently unknown to the compiler and \ - may have meaning added to it in the future", attr.path); - gate_feature!(self, custom_attribute, attr.span, &msg); - } - } -} - -pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { - let cx = Context { features, parse_sess, plugin_attributes: &[] }; - cx.check_attribute( - attr, - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)), - true - ); -} - -fn find_lang_feature_issue(feature: Symbol) -> Option { - if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { - let issue = info.2; - // FIXME (#28244): enforce that active features have issue numbers - // assert!(issue.is_some()) - issue - } else { - // search in Accepted, Removed, or Stable Removed features - let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) - .find(|t| t.0 == feature); - match found { - Some(&(_, _, issue, _)) => issue, - None => panic!("Feature `{}` is not declared anywhere", feature), - } - } -} - -pub enum GateIssue { - Language, - Library(Option) -} - -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum GateStrength { - /// A hard error. (Most feature gates should use this.) - Hard, - /// Only a warning. (Use this only as backwards-compatibility demands.) - Soft, -} - -pub fn emit_feature_err( - sess: &ParseSess, - feature: Symbol, - span: Span, - issue: GateIssue, - explain: &str, -) { - feature_err(sess, feature, span, issue, explain).emit(); -} - -pub fn feature_err<'a, S: Into>( - sess: &'a ParseSess, - feature: Symbol, - span: S, - issue: GateIssue, - explain: &str, -) -> DiagnosticBuilder<'a> { - leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) -} - -fn leveled_feature_err<'a, S: Into>( - sess: &'a ParseSess, - feature: Symbol, - span: S, - issue: GateIssue, - explain: &str, - level: GateStrength, -) -> DiagnosticBuilder<'a> { - let diag = &sess.span_diagnostic; - - let issue = match issue { - GateIssue::Language => find_lang_feature_issue(feature), - GateIssue::Library(lib) => lib, - }; - - let mut err = match level { - GateStrength::Hard => { - diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) - } - GateStrength::Soft => diag.struct_span_warn(span, explain), - }; - - match issue { - None | Some(0) => {} // We still accept `0` as a stand-in for backwards compatibility - Some(n) => { - err.note(&format!( - "for more information, see https://github.com/rust-lang/rust/issues/{}", - n, - )); - } - } - - // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if sess.unstable_features.is_nightly_build() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); - } - - // If we're on stable and only emitting a "soft" warning, add a note to - // clarify that the feature isn't "on" (rather than being on but - // warning-worthy). - if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft { - err.help("a nightly build of the compiler is required to enable this feature"); - } - - err - -} - -const EXPLAIN_BOX_SYNTAX: &str = - "box expression syntax is experimental; you can call `Box::new` instead"; - -pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = - "attributes on expressions are experimental"; - -pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str = - "allow_internal_unstable side-steps feature gating and stability checks"; -pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str = - "allow_internal_unsafe side-steps the unsafe_code lint"; - -pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str = - "unsized tuple coercion is not stable enough for use and is subject to change"; - -struct PostExpansionVisitor<'a> { - context: &'a Context<'a>, - builtin_attributes: &'static FxHashMap, -} - -macro_rules! gate_feature_post { - ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ - let (cx, span) = ($cx, $span); - if !span.allows_unstable(sym::$feature) { - gate_feature!(cx.context, $feature, span, $explain) - } - }}; - ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ - let (cx, span) = ($cx, $span); - if !span.allows_unstable(sym::$feature) { - gate_feature!(cx.context, $feature, span, $explain, $level) - } - }} -} - -impl<'a> PostExpansionVisitor<'a> { - fn check_abi(&self, abi: Abi, span: Span) { - match abi { - Abi::RustIntrinsic => { - gate_feature_post!(&self, intrinsics, span, - "intrinsics are subject to change"); - }, - Abi::PlatformIntrinsic => { - gate_feature_post!(&self, platform_intrinsics, span, - "platform intrinsics are experimental and possibly buggy"); - }, - Abi::Vectorcall => { - gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change"); - }, - Abi::Thiscall => { - gate_feature_post!(&self, abi_thiscall, span, - "thiscall is experimental and subject to change"); - }, - Abi::RustCall => { - gate_feature_post!(&self, unboxed_closures, span, - "rust-call ABI is subject to change"); - }, - Abi::PtxKernel => { - gate_feature_post!(&self, abi_ptx, span, - "PTX ABIs are experimental and subject to change"); - }, - Abi::Unadjusted => { - gate_feature_post!(&self, abi_unadjusted, span, - "unadjusted ABI is an implementation detail and perma-unstable"); - }, - Abi::Msp430Interrupt => { - gate_feature_post!(&self, abi_msp430_interrupt, span, - "msp430-interrupt ABI is experimental and subject to change"); - }, - Abi::X86Interrupt => { - gate_feature_post!(&self, abi_x86_interrupt, span, - "x86-interrupt ABI is experimental and subject to change"); - }, - Abi::AmdGpuKernel => { - gate_feature_post!(&self, abi_amdgpu_kernel, span, - "amdgpu-kernel ABI is experimental and subject to change"); - }, - // Stable - Abi::Cdecl | - Abi::Stdcall | - Abi::Fastcall | - Abi::Aapcs | - Abi::Win64 | - Abi::SysV64 | - Abi::Rust | - Abi::C | - Abi::System => {} - } - } -} - -impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { - fn visit_attribute(&mut self, attr: &ast::Attribute) { - let attr_info = attr.ident().and_then(|ident| { - self.builtin_attributes.get(&ident.name).map(|a| *a) - }); - - // Check for gated attributes. - self.context.check_attribute(attr, attr_info, false); - - if attr.check_name(sym::doc) { - if let Some(content) = attr.meta_item_list() { - if content.len() == 1 && content[0].check_name(sym::cfg) { - gate_feature_post!(&self, doc_cfg, attr.span, - "`#[doc(cfg(...))]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::masked)) { - gate_feature_post!(&self, doc_masked, attr.span, - "`#[doc(masked)]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::spotlight)) { - gate_feature_post!(&self, doc_spotlight, attr.span, - "`#[doc(spotlight)]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::alias)) { - gate_feature_post!(&self, doc_alias, attr.span, - "`#[doc(alias = \"...\")]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::keyword)) { - gate_feature_post!(&self, doc_keyword, attr.span, - "`#[doc(keyword = \"...\")]` is experimental" - ); - } - } - } - - match attr_info { - // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. - Some(&(name, _, template, _)) if name != sym::rustc_dummy => - check_builtin_attribute(self.context.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { - if token == token::Eq { - // All key-value attributes are restricted to meta-item syntax. - attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok(); - } - } - } - } - - fn visit_name(&mut self, sp: Span, name: ast::Name) { - if !name.as_str().is_ascii() { - gate_feature_post!( - &self, - non_ascii_idents, - self.context.parse_sess.source_map().def_span(sp), - "non-ascii idents are not fully supported" - ); - } - } - - fn visit_item(&mut self, i: &'a ast::Item) { - match i.node { - ast::ItemKind::ForeignMod(ref foreign_module) => { - self.check_abi(foreign_module.abi, i.span); - } - - ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { - gate_feature_post!(&self, plugin_registrar, i.span, - "compiler plugins are experimental and possibly buggy"); - } - if attr::contains_name(&i.attrs[..], sym::start) { - gate_feature_post!(&self, start, i.span, - "a `#[start]` function is an experimental \ - feature whose signature may change \ - over time"); - } - if attr::contains_name(&i.attrs[..], sym::main) { - gate_feature_post!(&self, main, i.span, - "declaration of a non-standard `#[main]` \ - function may change over time, for now \ - a top-level `fn main()` is required"); - } - } - - ast::ItemKind::Struct(..) => { - for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { - for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(sym::simd) { - gate_feature_post!(&self, repr_simd, attr.span, - "SIMD types are experimental and possibly buggy"); - } - } - } - } - - ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => { - for variant in variants { - match (&variant.data, &variant.disr_expr) { - (ast::VariantData::Unit(..), _) => {}, - (_, Some(disr_expr)) => - gate_feature_post!( - &self, - arbitrary_enum_discriminant, - disr_expr.value.span, - "discriminants on non-unit variants are experimental"), - _ => {}, - } - } - - let has_feature = self.context.features.arbitrary_enum_discriminant; - if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { - Parser::maybe_report_invalid_custom_discriminants( - self.context.parse_sess, - &variants, - ); - } - } - - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { - if polarity == ast::ImplPolarity::Negative { - gate_feature_post!(&self, optin_builtin_traits, - i.span, - "negative trait bounds are not yet fully implemented; \ - use marker types for now"); - } - - if let ast::Defaultness::Default = defaultness { - gate_feature_post!(&self, specialization, - i.span, - "specialization is unstable"); - } - } - - ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { - gate_feature_post!(&self, optin_builtin_traits, - i.span, - "auto traits are experimental and possibly buggy"); - } - - ast::ItemKind::TraitAlias(..) => { - gate_feature_post!( - &self, - trait_alias, - i.span, - "trait aliases are experimental" - ); - } - - ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { - let msg = "`macro` is experimental"; - gate_feature_post!(&self, decl_macro, i.span, msg); - } - - ast::ItemKind::OpaqueTy(..) => { - gate_feature_post!( - &self, - type_alias_impl_trait, - i.span, - "`impl Trait` in type aliases is unstable" - ); - } - - _ => {} - } - - visit::walk_item(self, i); - } - - fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { - match i.node { - ast::ForeignItemKind::Fn(..) | - ast::ForeignItemKind::Static(..) => { - let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); - let links_to_llvm = match link_name { - Some(val) => val.as_str().starts_with("llvm."), - _ => false - }; - if links_to_llvm { - gate_feature_post!(&self, link_llvm_intrinsics, i.span, - "linking to LLVM intrinsics is experimental"); - } - } - ast::ForeignItemKind::Ty => { - gate_feature_post!(&self, extern_types, i.span, - "extern types are experimental"); - } - ast::ForeignItemKind::Macro(..) => {} - } - - visit::walk_foreign_item(self, i) - } - - fn visit_ty(&mut self, ty: &'a ast::Ty) { - match ty.node { - ast::TyKind::BareFn(ref bare_fn_ty) => { - self.check_abi(bare_fn_ty.abi, ty.span); - } - ast::TyKind::Never => { - gate_feature_post!(&self, never_type, ty.span, - "The `!` type is experimental"); - } - _ => {} - } - visit::walk_ty(self, ty) - } - - fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { - if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { - if let ast::TyKind::Never = output_ty.node { - // Do nothing. - } else { - self.visit_ty(output_ty) - } - } - } - - fn visit_expr(&mut self, e: &'a ast::Expr) { - match e.node { - ast::ExprKind::Box(_) => { - gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); - } - ast::ExprKind::Type(..) => { - // To avoid noise about type ascription in common syntax errors, only emit if it - // is the *only* error. - if self.context.parse_sess.span_diagnostic.err_count() == 0 { - gate_feature_post!(&self, type_ascription, e.span, - "type ascription is experimental"); - } - } - ast::ExprKind::TryBlock(_) => { - gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); - } - ast::ExprKind::Block(_, opt_label) => { - if let Some(label) = opt_label { - gate_feature_post!(&self, label_break_value, label.ident.span, - "labels on blocks are unstable"); - } - } - _ => {} - } - visit::walk_expr(self, e) - } - - fn visit_arm(&mut self, arm: &'a ast::Arm) { - visit::walk_arm(self, arm) - } - - fn visit_pat(&mut self, pattern: &'a ast::Pat) { - match &pattern.node { - PatKind::Slice(pats) => { - for pat in &*pats { - let span = pat.span; - let inner_pat = match &pat.node { - PatKind::Ident(.., Some(pat)) => pat, - _ => pat, - }; - if inner_pat.is_rest() { - gate_feature_post!( - &self, - slice_patterns, - span, - "subslice patterns are unstable" - ); - } - } - } - PatKind::Box(..) => { - gate_feature_post!(&self, box_patterns, - pattern.span, - "box pattern syntax is experimental"); - } - PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { - gate_feature_post!(&self, exclusive_range_pattern, pattern.span, - "exclusive range pattern syntax is experimental"); - } - _ => {} - } - visit::walk_pat(self, pattern) - } - - fn visit_fn(&mut self, - fn_kind: FnKind<'a>, - fn_decl: &'a ast::FnDecl, - span: Span, - _node_id: NodeId) { - if let Some(header) = fn_kind.header() { - // Stability of const fn methods are covered in - // `visit_trait_item` and `visit_impl_item` below; this is - // because default methods don't pass through this point. - self.check_abi(header.abi, span); - } - - if fn_decl.c_variadic { - gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); - } - - visit::walk_fn(self, fn_kind, fn_decl, span) - } - - fn visit_generic_param(&mut self, param: &'a GenericParam) { - match param.kind { - GenericParamKind::Const { .. } => - gate_feature_post!(&self, const_generics, param.ident.span, - "const generics are unstable"), - _ => {} - } - visit::walk_generic_param(self, param) - } - - fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { - match constraint.kind { - AssocTyConstraintKind::Bound { .. } => - gate_feature_post!(&self, associated_type_bounds, constraint.span, - "associated type bounds are unstable"), - _ => {} - } - visit::walk_assoc_ty_constraint(self, constraint) - } - - fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { - match ti.node { - ast::TraitItemKind::Method(ref sig, ref block) => { - if block.is_none() { - self.check_abi(sig.header.abi, ti.span); - } - if sig.decl.c_variadic { - gate_feature_post!(&self, c_variadic, ti.span, - "C-variadic functions are unstable"); - } - if sig.header.constness.node == ast::Constness::Const { - gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); - } - } - ast::TraitItemKind::Type(_, ref default) => { - // We use three if statements instead of something like match guards so that all - // of these errors can be emitted if all cases apply. - if default.is_some() { - gate_feature_post!(&self, associated_type_defaults, ti.span, - "associated type defaults are unstable"); - } - if !ti.generics.params.is_empty() { - gate_feature_post!(&self, generic_associated_types, ti.span, - "generic associated types are unstable"); - } - if !ti.generics.where_clause.predicates.is_empty() { - gate_feature_post!(&self, generic_associated_types, ti.span, - "where clauses on associated types are unstable"); - } - } - _ => {} - } - visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { - if ii.defaultness == ast::Defaultness::Default { - gate_feature_post!(&self, specialization, - ii.span, - "specialization is unstable"); - } - - match ii.node { - ast::ImplItemKind::Method(..) => {} - ast::ImplItemKind::OpaqueTy(..) => { - gate_feature_post!( - &self, - type_alias_impl_trait, - ii.span, - "`impl Trait` in type aliases is unstable" - ); - } - ast::ImplItemKind::TyAlias(_) => { - if !ii.generics.params.is_empty() { - gate_feature_post!(&self, generic_associated_types, ii.span, - "generic associated types are unstable"); - } - if !ii.generics.where_clause.predicates.is_empty() { - gate_feature_post!(&self, generic_associated_types, ii.span, - "where clauses on associated types are unstable"); - } - } - _ => {} - } - visit::walk_impl_item(self, ii) - } - - fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { - gate_feature_post!(&self, crate_visibility_modifier, vis.span, - "`crate` visibility modifier is experimental"); - } - visit::walk_vis(self, vis) - } -} - -pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], - crate_edition: Edition, allow_features: &Option>) -> Features { - fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { - let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); - if let Some(reason) = reason { - err.span_note(span, reason); - } else { - err.span_label(span, "feature has been removed"); - } - err.emit(); - } - - let mut features = Features::new(); - let mut edition_enabled_features = FxHashMap::default(); - - for &edition in ALL_EDITIONS { - if edition <= crate_edition { - // The `crate_edition` implies its respective umbrella feature-gate - // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). - edition_enabled_features.insert(edition.feature_name(), edition); - } - } - - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= crate_edition { - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, crate_edition); - } - } - } - - // Process the edition umbrella feature-gates first, to ensure - // `edition_enabled_features` is completed before it's queried. - for attr in krate_attrs { - if !attr.check_name(sym::feature) { - continue - } - - let list = match attr.meta_item_list() { - Some(list) => list, - None => continue, - }; - - for mi in list { - if !mi.is_word() { - continue; - } - - let name = mi.name_or_empty(); - - if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) { - if *edition <= crate_edition { - continue; - } - - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= *edition { - // FIXME(Manishearth) there is currently no way to set - // lib features by edition - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, *edition); - } - } - } - } - } - } - - for attr in krate_attrs { - if !attr.check_name(sym::feature) { - continue - } - - let list = match attr.meta_item_list() { - Some(list) => list, - None => continue, - }; - - let bad_input = |span| { - struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") - }; - - for mi in list { - let name = match mi.ident() { - Some(ident) if mi.is_word() => ident.name, - Some(ident) => { - bad_input(mi.span()).span_suggestion( - mi.span(), - "expected just one word", - format!("{}", ident.name), - Applicability::MaybeIncorrect, - ).emit(); - continue - } - None => { - bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); - continue - } - }; - - if let Some(edition) = edition_enabled_features.get(&name) { - struct_span_warn!( - span_handler, - mi.span(), - E0705, - "the feature `{}` is included in the Rust {} edition", - name, - edition, - ).emit(); - continue; - } - - if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { - // Handled in the separate loop above. - continue; - } - - let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); - let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); - if let Some((.., reason)) = removed.or(stable_removed) { - feature_removed(span_handler, mi.span(), *reason); - continue; - } - - if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { - let since = Some(Symbol::intern(since)); - features.declared_lang_features.push((name, mi.span(), since)); - continue; - } - - if let Some(allowed) = allow_features.as_ref() { - if allowed.iter().find(|f| *f == name.as_str()).is_none() { - span_err!(span_handler, mi.span(), E0725, - "the feature `{}` is not in the list of allowed features", - name); - continue; - } - } - - if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { - set(&mut features, mi.span()); - features.declared_lang_features.push((name, mi.span(), None)); - continue; - } - - features.declared_lib_features.push((name, mi.span())); - } - } - - features -} - -pub fn check_crate(krate: &ast::Crate, - sess: &ParseSess, - features: &Features, - plugin_attributes: &[(Symbol, AttributeType)], - unstable: UnstableFeatures) { - maybe_stage_features(&sess.span_diagnostic, krate, unstable); - let ctx = Context { - features, - parse_sess: sess, - plugin_attributes, - }; - - macro_rules! gate_all { - ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); }; - ($spans:ident, $gate:ident, $msg:literal) => { - for span in &*sess.gated_spans.$spans.borrow() { - gate_feature!(&ctx, $gate, *span, $msg); - } - } - } - - gate_all!(param_attrs, "attributes on function parameters are unstable"); - gate_all!(let_chains, "`let` expressions in this position are experimental"); - gate_all!(async_closure, "async closures are unstable"); - gate_all!(yields, generators, "yield syntax is experimental"); - gate_all!(or_patterns, "or-patterns syntax is experimental"); - - let visitor = &mut PostExpansionVisitor { - context: &ctx, - builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, - }; - visit::walk_crate(visitor, krate); -} - -#[derive(Clone, Copy, Hash)] -pub enum UnstableFeatures { - /// Hard errors for unstable features are active, as on beta/stable channels. - Disallow, - /// Allow features to be activated, as on nightly. - Allow, - /// Errors are bypassed for bootstrapping. This is required any time - /// during the build that feature-related lints are set to warn or above - /// because the build turns on warnings-as-errors and uses lots of unstable - /// features. As a result, this is always required for building Rust itself. - Cheat -} - -impl UnstableFeatures { - pub fn from_environment() -> UnstableFeatures { - // Whether this is a feature-staged build, i.e., on the beta or stable channel - let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); - // Whether we should enable unstable features for bootstrapping - let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); - match (disable_unstable_features, bootstrap) { - (_, true) => UnstableFeatures::Cheat, - (true, _) => UnstableFeatures::Disallow, - (false, _) => UnstableFeatures::Allow - } - } - - pub fn is_nightly_build(&self) -> bool { - match *self { - UnstableFeatures::Allow | UnstableFeatures::Cheat => true, - _ => false, - } - } -} - -fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, - unstable: UnstableFeatures) { - let allow_features = match unstable { - UnstableFeatures::Allow => true, - UnstableFeatures::Disallow => false, - UnstableFeatures::Cheat => true - }; - if !allow_features { - for attr in &krate.attrs { - if attr.check_name(sym::feature) { - let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); - span_err!(span_handler, attr.span, E0554, - "`#![feature]` may not be used on the {} release channel", - release_channel); - } - } - } -} diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index 9b347711fdd..b934f2e7f64 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -3,8 +3,8 @@ use AttributeType::*; use AttributeGate::*; -use super::{emit_feature_err, GateIssue}; -use super::{Stability, EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE}; +use super::check::{emit_feature_err, GateIssue}; +use super::check::{Stability, EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE}; use super::active::Features; use crate::ast; diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs new file mode 100644 index 00000000000..d82b287b6fb --- /dev/null +++ b/src/libsyntax/feature_gate/check.rs @@ -0,0 +1,951 @@ +use super::active::{ACTIVE_FEATURES, Features}; +use super::accepted::ACCEPTED_FEATURES; +use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; +use super::builtin_attrs::{AttributeGate, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; + +use crate::ast::{ + self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, + PatKind, RangeEnd, +}; +use crate::attr::{self, check_builtin_attribute}; +use crate::source_map::Spanned; +use crate::edition::{ALL_EDITIONS, Edition}; +use crate::visit::{self, FnKind, Visitor}; +use crate::parse::{token, ParseSess}; +use crate::parse::parser::Parser; +use crate::symbol::{Symbol, sym}; +use crate::tokenstream::TokenTree; + +use errors::{Applicability, DiagnosticBuilder, Handler}; +use rustc_data_structures::fx::FxHashMap; +use rustc_target::spec::abi::Abi; +use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use log::debug; + +use std::env; + +#[derive(Copy, Clone, Debug)] +pub enum Stability { + Unstable, + // First argument is tracking issue link; second argument is an optional + // help message, which defaults to "remove this attribute" + Deprecated(&'static str, Option<&'static str>), +} + +struct Context<'a> { + features: &'a Features, + parse_sess: &'a ParseSess, + plugin_attributes: &'a [(Symbol, AttributeType)], +} + +macro_rules! gate_feature_fn { + ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ + let (cx, has_feature, span, + name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level); + let has_feature: bool = has_feature(&$cx.features); + debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); + if !has_feature && !span.allows_unstable($name) { + leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level) + .emit(); + } + }} +} + +macro_rules! gate_feature { + ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, + sym::$feature, $explain, GateStrength::Hard) + }; + ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, + sym::$feature, $explain, $level) + }; +} + +impl<'a> Context<'a> { + fn check_attribute( + &self, + attr: &ast::Attribute, + attr_info: Option<&BuiltinAttribute>, + is_macro: bool + ) { + debug!("check_attribute(attr = {:?})", attr); + if let Some(&(name, ty, _template, ref gateage)) = attr_info { + if let AttributeGate::Gated(_, name, desc, ref has_feature) = *gateage { + if !attr.span.allows_unstable(name) { + gate_feature_fn!( + self, has_feature, attr.span, name, desc, GateStrength::Hard + ); + } + } else if name == sym::doc { + if let Some(content) = attr.meta_item_list() { + if content.iter().any(|c| c.check_name(sym::include)) { + gate_feature!(self, external_doc, attr.span, + "`#[doc(include = \"...\")]` is experimental" + ); + } + } + } + debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); + return; + } else { + for segment in &attr.path.segments { + if segment.ident.as_str().starts_with("rustc") { + let msg = "attributes starting with `rustc` are \ + reserved for use by the `rustc` compiler"; + gate_feature!(self, rustc_attrs, segment.ident.span, msg); + } + } + } + for &(n, ty) in self.plugin_attributes { + if attr.path == n { + // Plugins can't gate attributes, so we don't check for it + // unlike the code above; we only use this loop to + // short-circuit to avoid the checks below. + debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty); + return; + } + } + if !is_macro && !attr::is_known(attr) { + // Only run the custom attribute lint during regular feature gate + // checking. Macro gating runs before the plugin attributes are + // registered, so we skip this in that case. + let msg = format!("the attribute `{}` is currently unknown to the compiler and \ + may have meaning added to it in the future", attr.path); + gate_feature!(self, custom_attribute, attr.span, &msg); + } + } +} + +pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { + let cx = Context { features, parse_sess, plugin_attributes: &[] }; + cx.check_attribute( + attr, + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)), + true + ); +} + +fn find_lang_feature_issue(feature: Symbol) -> Option { + if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { + let issue = info.2; + // FIXME (#28244): enforce that active features have issue numbers + // assert!(issue.is_some()) + issue + } else { + // search in Accepted, Removed, or Stable Removed features + let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) + .find(|t| t.0 == feature); + match found { + Some(&(_, _, issue, _)) => issue, + None => panic!("Feature `{}` is not declared anywhere", feature), + } + } +} + +pub enum GateIssue { + Language, + Library(Option) +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum GateStrength { + /// A hard error. (Most feature gates should use this.) + Hard, + /// Only a warning. (Use this only as backwards-compatibility demands.) + Soft, +} + +pub fn emit_feature_err( + sess: &ParseSess, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &str, +) { + feature_err(sess, feature, span, issue, explain).emit(); +} + +pub fn feature_err<'a, S: Into>( + sess: &'a ParseSess, + feature: Symbol, + span: S, + issue: GateIssue, + explain: &str, +) -> DiagnosticBuilder<'a> { + leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) +} + +fn leveled_feature_err<'a, S: Into>( + sess: &'a ParseSess, + feature: Symbol, + span: S, + issue: GateIssue, + explain: &str, + level: GateStrength, +) -> DiagnosticBuilder<'a> { + let diag = &sess.span_diagnostic; + + let issue = match issue { + GateIssue::Language => find_lang_feature_issue(feature), + GateIssue::Library(lib) => lib, + }; + + let mut err = match level { + GateStrength::Hard => { + diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) + } + GateStrength::Soft => diag.struct_span_warn(span, explain), + }; + + match issue { + None | Some(0) => {} // We still accept `0` as a stand-in for backwards compatibility + Some(n) => { + err.note(&format!( + "for more information, see https://github.com/rust-lang/rust/issues/{}", + n, + )); + } + } + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.unstable_features.is_nightly_build() { + err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); + } + + // If we're on stable and only emitting a "soft" warning, add a note to + // clarify that the feature isn't "on" (rather than being on but + // warning-worthy). + if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft { + err.help("a nightly build of the compiler is required to enable this feature"); + } + + err + +} + +const EXPLAIN_BOX_SYNTAX: &str = + "box expression syntax is experimental; you can call `Box::new` instead"; + +pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = + "attributes on expressions are experimental"; + +pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str = + "allow_internal_unstable side-steps feature gating and stability checks"; +pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str = + "allow_internal_unsafe side-steps the unsafe_code lint"; + +pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str = + "unsized tuple coercion is not stable enough for use and is subject to change"; + +struct PostExpansionVisitor<'a> { + context: &'a Context<'a>, + builtin_attributes: &'static FxHashMap, +} + +macro_rules! gate_feature_post { + ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ + let (cx, span) = ($cx, $span); + if !span.allows_unstable(sym::$feature) { + gate_feature!(cx.context, $feature, span, $explain) + } + }}; + ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ + let (cx, span) = ($cx, $span); + if !span.allows_unstable(sym::$feature) { + gate_feature!(cx.context, $feature, span, $explain, $level) + } + }} +} + +impl<'a> PostExpansionVisitor<'a> { + fn check_abi(&self, abi: Abi, span: Span) { + match abi { + Abi::RustIntrinsic => { + gate_feature_post!(&self, intrinsics, span, + "intrinsics are subject to change"); + }, + Abi::PlatformIntrinsic => { + gate_feature_post!(&self, platform_intrinsics, span, + "platform intrinsics are experimental and possibly buggy"); + }, + Abi::Vectorcall => { + gate_feature_post!(&self, abi_vectorcall, span, + "vectorcall is experimental and subject to change"); + }, + Abi::Thiscall => { + gate_feature_post!(&self, abi_thiscall, span, + "thiscall is experimental and subject to change"); + }, + Abi::RustCall => { + gate_feature_post!(&self, unboxed_closures, span, + "rust-call ABI is subject to change"); + }, + Abi::PtxKernel => { + gate_feature_post!(&self, abi_ptx, span, + "PTX ABIs are experimental and subject to change"); + }, + Abi::Unadjusted => { + gate_feature_post!(&self, abi_unadjusted, span, + "unadjusted ABI is an implementation detail and perma-unstable"); + }, + Abi::Msp430Interrupt => { + gate_feature_post!(&self, abi_msp430_interrupt, span, + "msp430-interrupt ABI is experimental and subject to change"); + }, + Abi::X86Interrupt => { + gate_feature_post!(&self, abi_x86_interrupt, span, + "x86-interrupt ABI is experimental and subject to change"); + }, + Abi::AmdGpuKernel => { + gate_feature_post!(&self, abi_amdgpu_kernel, span, + "amdgpu-kernel ABI is experimental and subject to change"); + }, + // Stable + Abi::Cdecl | + Abi::Stdcall | + Abi::Fastcall | + Abi::Aapcs | + Abi::Win64 | + Abi::SysV64 | + Abi::Rust | + Abi::C | + Abi::System => {} + } + } +} + +impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { + fn visit_attribute(&mut self, attr: &ast::Attribute) { + let attr_info = attr.ident().and_then(|ident| { + self.builtin_attributes.get(&ident.name).map(|a| *a) + }); + + // Check for gated attributes. + self.context.check_attribute(attr, attr_info, false); + + if attr.check_name(sym::doc) { + if let Some(content) = attr.meta_item_list() { + if content.len() == 1 && content[0].check_name(sym::cfg) { + gate_feature_post!(&self, doc_cfg, attr.span, + "`#[doc(cfg(...))]` is experimental" + ); + } else if content.iter().any(|c| c.check_name(sym::masked)) { + gate_feature_post!(&self, doc_masked, attr.span, + "`#[doc(masked)]` is experimental" + ); + } else if content.iter().any(|c| c.check_name(sym::spotlight)) { + gate_feature_post!(&self, doc_spotlight, attr.span, + "`#[doc(spotlight)]` is experimental" + ); + } else if content.iter().any(|c| c.check_name(sym::alias)) { + gate_feature_post!(&self, doc_alias, attr.span, + "`#[doc(alias = \"...\")]` is experimental" + ); + } else if content.iter().any(|c| c.check_name(sym::keyword)) { + gate_feature_post!(&self, doc_keyword, attr.span, + "`#[doc(keyword = \"...\")]` is experimental" + ); + } + } + } + + match attr_info { + // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. + Some(&(name, _, template, _)) if name != sym::rustc_dummy => + check_builtin_attribute(self.context.parse_sess, attr, name, template), + _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { + if token == token::Eq { + // All key-value attributes are restricted to meta-item syntax. + attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok(); + } + } + } + } + + fn visit_name(&mut self, sp: Span, name: ast::Name) { + if !name.as_str().is_ascii() { + gate_feature_post!( + &self, + non_ascii_idents, + self.context.parse_sess.source_map().def_span(sp), + "non-ascii idents are not fully supported" + ); + } + } + + fn visit_item(&mut self, i: &'a ast::Item) { + match i.node { + ast::ItemKind::ForeignMod(ref foreign_module) => { + self.check_abi(foreign_module.abi, i.span); + } + + ast::ItemKind::Fn(..) => { + if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { + gate_feature_post!(&self, plugin_registrar, i.span, + "compiler plugins are experimental and possibly buggy"); + } + if attr::contains_name(&i.attrs[..], sym::start) { + gate_feature_post!(&self, start, i.span, + "a `#[start]` function is an experimental \ + feature whose signature may change \ + over time"); + } + if attr::contains_name(&i.attrs[..], sym::main) { + gate_feature_post!(&self, main, i.span, + "declaration of a non-standard `#[main]` \ + function may change over time, for now \ + a top-level `fn main()` is required"); + } + } + + ast::ItemKind::Struct(..) => { + for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + if item.check_name(sym::simd) { + gate_feature_post!(&self, repr_simd, attr.span, + "SIMD types are experimental and possibly buggy"); + } + } + } + } + + ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => { + for variant in variants { + match (&variant.data, &variant.disr_expr) { + (ast::VariantData::Unit(..), _) => {}, + (_, Some(disr_expr)) => + gate_feature_post!( + &self, + arbitrary_enum_discriminant, + disr_expr.value.span, + "discriminants on non-unit variants are experimental"), + _ => {}, + } + } + + let has_feature = self.context.features.arbitrary_enum_discriminant; + if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { + Parser::maybe_report_invalid_custom_discriminants( + self.context.parse_sess, + &variants, + ); + } + } + + ast::ItemKind::Impl(_, polarity, defaultness, ..) => { + if polarity == ast::ImplPolarity::Negative { + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "negative trait bounds are not yet fully implemented; \ + use marker types for now"); + } + + if let ast::Defaultness::Default = defaultness { + gate_feature_post!(&self, specialization, + i.span, + "specialization is unstable"); + } + } + + ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "auto traits are experimental and possibly buggy"); + } + + ast::ItemKind::TraitAlias(..) => { + gate_feature_post!( + &self, + trait_alias, + i.span, + "trait aliases are experimental" + ); + } + + ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { + let msg = "`macro` is experimental"; + gate_feature_post!(&self, decl_macro, i.span, msg); + } + + ast::ItemKind::OpaqueTy(..) => { + gate_feature_post!( + &self, + type_alias_impl_trait, + i.span, + "`impl Trait` in type aliases is unstable" + ); + } + + _ => {} + } + + visit::walk_item(self, i); + } + + fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { + match i.node { + ast::ForeignItemKind::Fn(..) | + ast::ForeignItemKind::Static(..) => { + let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); + let links_to_llvm = match link_name { + Some(val) => val.as_str().starts_with("llvm."), + _ => false + }; + if links_to_llvm { + gate_feature_post!(&self, link_llvm_intrinsics, i.span, + "linking to LLVM intrinsics is experimental"); + } + } + ast::ForeignItemKind::Ty => { + gate_feature_post!(&self, extern_types, i.span, + "extern types are experimental"); + } + ast::ForeignItemKind::Macro(..) => {} + } + + visit::walk_foreign_item(self, i) + } + + fn visit_ty(&mut self, ty: &'a ast::Ty) { + match ty.node { + ast::TyKind::BareFn(ref bare_fn_ty) => { + self.check_abi(bare_fn_ty.abi, ty.span); + } + ast::TyKind::Never => { + gate_feature_post!(&self, never_type, ty.span, + "The `!` type is experimental"); + } + _ => {} + } + visit::walk_ty(self, ty) + } + + fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { + if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { + if let ast::TyKind::Never = output_ty.node { + // Do nothing. + } else { + self.visit_ty(output_ty) + } + } + } + + fn visit_expr(&mut self, e: &'a ast::Expr) { + match e.node { + ast::ExprKind::Box(_) => { + gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); + } + ast::ExprKind::Type(..) => { + // To avoid noise about type ascription in common syntax errors, only emit if it + // is the *only* error. + if self.context.parse_sess.span_diagnostic.err_count() == 0 { + gate_feature_post!(&self, type_ascription, e.span, + "type ascription is experimental"); + } + } + ast::ExprKind::TryBlock(_) => { + gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); + } + ast::ExprKind::Block(_, opt_label) => { + if let Some(label) = opt_label { + gate_feature_post!(&self, label_break_value, label.ident.span, + "labels on blocks are unstable"); + } + } + _ => {} + } + visit::walk_expr(self, e) + } + + fn visit_arm(&mut self, arm: &'a ast::Arm) { + visit::walk_arm(self, arm) + } + + fn visit_pat(&mut self, pattern: &'a ast::Pat) { + match &pattern.node { + PatKind::Slice(pats) => { + for pat in &*pats { + let span = pat.span; + let inner_pat = match &pat.node { + PatKind::Ident(.., Some(pat)) => pat, + _ => pat, + }; + if inner_pat.is_rest() { + gate_feature_post!( + &self, + slice_patterns, + span, + "subslice patterns are unstable" + ); + } + } + } + PatKind::Box(..) => { + gate_feature_post!(&self, box_patterns, + pattern.span, + "box pattern syntax is experimental"); + } + PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { + gate_feature_post!(&self, exclusive_range_pattern, pattern.span, + "exclusive range pattern syntax is experimental"); + } + _ => {} + } + visit::walk_pat(self, pattern) + } + + fn visit_fn(&mut self, + fn_kind: FnKind<'a>, + fn_decl: &'a ast::FnDecl, + span: Span, + _node_id: NodeId) { + if let Some(header) = fn_kind.header() { + // Stability of const fn methods are covered in + // `visit_trait_item` and `visit_impl_item` below; this is + // because default methods don't pass through this point. + self.check_abi(header.abi, span); + } + + if fn_decl.c_variadic { + gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); + } + + visit::walk_fn(self, fn_kind, fn_decl, span) + } + + fn visit_generic_param(&mut self, param: &'a GenericParam) { + match param.kind { + GenericParamKind::Const { .. } => + gate_feature_post!(&self, const_generics, param.ident.span, + "const generics are unstable"), + _ => {} + } + visit::walk_generic_param(self, param) + } + + fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { + match constraint.kind { + AssocTyConstraintKind::Bound { .. } => + gate_feature_post!(&self, associated_type_bounds, constraint.span, + "associated type bounds are unstable"), + _ => {} + } + visit::walk_assoc_ty_constraint(self, constraint) + } + + fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { + match ti.node { + ast::TraitItemKind::Method(ref sig, ref block) => { + if block.is_none() { + self.check_abi(sig.header.abi, ti.span); + } + if sig.decl.c_variadic { + gate_feature_post!(&self, c_variadic, ti.span, + "C-variadic functions are unstable"); + } + if sig.header.constness.node == ast::Constness::Const { + gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); + } + } + ast::TraitItemKind::Type(_, ref default) => { + // We use three if statements instead of something like match guards so that all + // of these errors can be emitted if all cases apply. + if default.is_some() { + gate_feature_post!(&self, associated_type_defaults, ti.span, + "associated type defaults are unstable"); + } + if !ti.generics.params.is_empty() { + gate_feature_post!(&self, generic_associated_types, ti.span, + "generic associated types are unstable"); + } + if !ti.generics.where_clause.predicates.is_empty() { + gate_feature_post!(&self, generic_associated_types, ti.span, + "where clauses on associated types are unstable"); + } + } + _ => {} + } + visit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { + if ii.defaultness == ast::Defaultness::Default { + gate_feature_post!(&self, specialization, + ii.span, + "specialization is unstable"); + } + + match ii.node { + ast::ImplItemKind::Method(..) => {} + ast::ImplItemKind::OpaqueTy(..) => { + gate_feature_post!( + &self, + type_alias_impl_trait, + ii.span, + "`impl Trait` in type aliases is unstable" + ); + } + ast::ImplItemKind::TyAlias(_) => { + if !ii.generics.params.is_empty() { + gate_feature_post!(&self, generic_associated_types, ii.span, + "generic associated types are unstable"); + } + if !ii.generics.where_clause.predicates.is_empty() { + gate_feature_post!(&self, generic_associated_types, ii.span, + "where clauses on associated types are unstable"); + } + } + _ => {} + } + visit::walk_impl_item(self, ii) + } + + fn visit_vis(&mut self, vis: &'a ast::Visibility) { + if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { + gate_feature_post!(&self, crate_visibility_modifier, vis.span, + "`crate` visibility modifier is experimental"); + } + visit::walk_vis(self, vis) + } +} + +pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], + crate_edition: Edition, allow_features: &Option>) -> Features { + fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { + let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); + if let Some(reason) = reason { + err.span_note(span, reason); + } else { + err.span_label(span, "feature has been removed"); + } + err.emit(); + } + + let mut features = Features::new(); + let mut edition_enabled_features = FxHashMap::default(); + + for &edition in ALL_EDITIONS { + if edition <= crate_edition { + // The `crate_edition` implies its respective umbrella feature-gate + // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). + edition_enabled_features.insert(edition.feature_name(), edition); + } + } + + for &(name, .., f_edition, set) in ACTIVE_FEATURES { + if let Some(f_edition) = f_edition { + if f_edition <= crate_edition { + set(&mut features, DUMMY_SP); + edition_enabled_features.insert(name, crate_edition); + } + } + } + + // Process the edition umbrella feature-gates first, to ensure + // `edition_enabled_features` is completed before it's queried. + for attr in krate_attrs { + if !attr.check_name(sym::feature) { + continue + } + + let list = match attr.meta_item_list() { + Some(list) => list, + None => continue, + }; + + for mi in list { + if !mi.is_word() { + continue; + } + + let name = mi.name_or_empty(); + + if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) { + if *edition <= crate_edition { + continue; + } + + for &(name, .., f_edition, set) in ACTIVE_FEATURES { + if let Some(f_edition) = f_edition { + if f_edition <= *edition { + // FIXME(Manishearth) there is currently no way to set + // lib features by edition + set(&mut features, DUMMY_SP); + edition_enabled_features.insert(name, *edition); + } + } + } + } + } + } + + for attr in krate_attrs { + if !attr.check_name(sym::feature) { + continue + } + + let list = match attr.meta_item_list() { + Some(list) => list, + None => continue, + }; + + let bad_input = |span| { + struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") + }; + + for mi in list { + let name = match mi.ident() { + Some(ident) if mi.is_word() => ident.name, + Some(ident) => { + bad_input(mi.span()).span_suggestion( + mi.span(), + "expected just one word", + format!("{}", ident.name), + Applicability::MaybeIncorrect, + ).emit(); + continue + } + None => { + bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); + continue + } + }; + + if let Some(edition) = edition_enabled_features.get(&name) { + struct_span_warn!( + span_handler, + mi.span(), + E0705, + "the feature `{}` is included in the Rust {} edition", + name, + edition, + ).emit(); + continue; + } + + if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { + // Handled in the separate loop above. + continue; + } + + let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); + let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); + if let Some((.., reason)) = removed.or(stable_removed) { + feature_removed(span_handler, mi.span(), *reason); + continue; + } + + if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { + let since = Some(Symbol::intern(since)); + features.declared_lang_features.push((name, mi.span(), since)); + continue; + } + + if let Some(allowed) = allow_features.as_ref() { + if allowed.iter().find(|f| *f == name.as_str()).is_none() { + span_err!(span_handler, mi.span(), E0725, + "the feature `{}` is not in the list of allowed features", + name); + continue; + } + } + + if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { + set(&mut features, mi.span()); + features.declared_lang_features.push((name, mi.span(), None)); + continue; + } + + features.declared_lib_features.push((name, mi.span())); + } + } + + features +} + +pub fn check_crate(krate: &ast::Crate, + sess: &ParseSess, + features: &Features, + plugin_attributes: &[(Symbol, AttributeType)], + unstable: UnstableFeatures) { + maybe_stage_features(&sess.span_diagnostic, krate, unstable); + let ctx = Context { + features, + parse_sess: sess, + plugin_attributes, + }; + + macro_rules! gate_all { + ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); }; + ($spans:ident, $gate:ident, $msg:literal) => { + for span in &*sess.gated_spans.$spans.borrow() { + gate_feature!(&ctx, $gate, *span, $msg); + } + } + } + + gate_all!(param_attrs, "attributes on function parameters are unstable"); + gate_all!(let_chains, "`let` expressions in this position are experimental"); + gate_all!(async_closure, "async closures are unstable"); + gate_all!(yields, generators, "yield syntax is experimental"); + gate_all!(or_patterns, "or-patterns syntax is experimental"); + + let visitor = &mut PostExpansionVisitor { + context: &ctx, + builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, + }; + visit::walk_crate(visitor, krate); +} + +#[derive(Clone, Copy, Hash)] +pub enum UnstableFeatures { + /// Hard errors for unstable features are active, as on beta/stable channels. + Disallow, + /// Allow features to be activated, as on nightly. + Allow, + /// Errors are bypassed for bootstrapping. This is required any time + /// during the build that feature-related lints are set to warn or above + /// because the build turns on warnings-as-errors and uses lots of unstable + /// features. As a result, this is always required for building Rust itself. + Cheat +} + +impl UnstableFeatures { + pub fn from_environment() -> UnstableFeatures { + // Whether this is a feature-staged build, i.e., on the beta or stable channel + let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + // Whether we should enable unstable features for bootstrapping + let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); + match (disable_unstable_features, bootstrap) { + (_, true) => UnstableFeatures::Cheat, + (true, _) => UnstableFeatures::Disallow, + (false, _) => UnstableFeatures::Allow + } + } + + pub fn is_nightly_build(&self) -> bool { + match *self { + UnstableFeatures::Allow | UnstableFeatures::Cheat => true, + _ => false, + } + } +} + +fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) { + let allow_features = match unstable { + UnstableFeatures::Allow => true, + UnstableFeatures::Disallow => false, + UnstableFeatures::Cheat => true + }; + if !allow_features { + for attr in &krate.attrs { + if attr.check_name(sym::feature) { + let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); + span_err!(span_handler, attr.span, E0554, + "`#![feature]` may not be used on the {} release channel", + release_channel); + } + } + } +} -- cgit 1.4.1-3-g733a5 From 6febb75ec8e0aeade9be97a1224bd6327b531524 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Aug 2019 23:49:55 +0200 Subject: syntax: move `feature_gate.rs`. --- src/libsyntax/feature_gate.rs | 31 ------------------------------- src/libsyntax/feature_gate/mod.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 src/libsyntax/feature_gate.rs create mode 100644 src/libsyntax/feature_gate/mod.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs deleted file mode 100644 index 97793bca1f5..00000000000 --- a/src/libsyntax/feature_gate.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! # Feature gating -//! -//! This module implements the gating necessary for preventing certain compiler -//! features from being used by default. This module will crawl a pre-expanded -//! AST to ensure that there are no features which are used that are not -//! enabled. -//! -//! Features are enabled in programs via the crate-level attributes of -//! `#![feature(...)]` with a comma-separated list of features. -//! -//! For the purpose of future feature-tracking, once code for detection of feature -//! gate usage is added, *do not remove it again* even once the feature -//! becomes stable. - -mod accepted; -mod removed; -mod active; -mod builtin_attrs; -mod check; - -pub use active::{Features, INCOMPLETE_FEATURES}; -pub use builtin_attrs::{ - AttributeGate, AttributeType, GatedCfg, - BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, - deprecated_attributes, is_builtin_attr, is_builtin_attr_name, -}; -pub use check::{ - check_attribute, check_crate, get_features, feature_err, emit_feature_err, - Stability, GateIssue, UnstableFeatures, - EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION, -}; diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs new file mode 100644 index 00000000000..97793bca1f5 --- /dev/null +++ b/src/libsyntax/feature_gate/mod.rs @@ -0,0 +1,31 @@ +//! # Feature gating +//! +//! This module implements the gating necessary for preventing certain compiler +//! features from being used by default. This module will crawl a pre-expanded +//! AST to ensure that there are no features which are used that are not +//! enabled. +//! +//! Features are enabled in programs via the crate-level attributes of +//! `#![feature(...)]` with a comma-separated list of features. +//! +//! For the purpose of future feature-tracking, once code for detection of feature +//! gate usage is added, *do not remove it again* even once the feature +//! becomes stable. + +mod accepted; +mod removed; +mod active; +mod builtin_attrs; +mod check; + +pub use active::{Features, INCOMPLETE_FEATURES}; +pub use builtin_attrs::{ + AttributeGate, AttributeType, GatedCfg, + BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + deprecated_attributes, is_builtin_attr, is_builtin_attr_name, +}; +pub use check::{ + check_attribute, check_crate, get_features, feature_err, emit_feature_err, + Stability, GateIssue, UnstableFeatures, + EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION, +}; -- cgit 1.4.1-3-g733a5 From c9619a4202bd013f1be2776c328937ddd643e7b7 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 24 Aug 2019 17:47:26 +0200 Subject: Use doc comments for feature gate descriptions This is just in preparation for future usage of these texts. --- src/libsyntax/feature_gate/accepted.rs | 218 +++++++++++------------ src/libsyntax/feature_gate/active.rs | 305 +++++++++++++++++---------------- src/libsyntax/feature_gate/removed.rs | 22 ++- 3 files changed, 284 insertions(+), 261 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs index 32a0b76d5f0..28e4d2c073c 100644 --- a/src/libsyntax/feature_gate/accepted.rs +++ b/src/libsyntax/feature_gate/accepted.rs @@ -3,7 +3,9 @@ use crate::symbol::{Symbol, sym}; macro_rules! declare_features { - ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { + ($( + $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None), + )+) => { /// Those language feature has since been Accepted (it was once Active) pub const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ $((sym::$feature, $ver, $issue, None)),+ @@ -16,11 +18,11 @@ declare_features! ( // feature-group-start: for testing purposes // ------------------------------------------------------------------------- - // A temporary feature gate used to enable parser extensions needed - // to bootstrap fix for #5723. + /// A temporary feature gate used to enable parser extensions needed + /// to bootstrap fix for #5723. (accepted, issue_5723_bootstrap, "1.0.0", None, None), - // These are used to test this portion of the compiler, - // they don't actually mean anything. + /// These are used to test this portion of the compiler, + /// they don't actually mean anything. (accepted, test_accepted_feature, "1.0.0", None, None), // ------------------------------------------------------------------------- @@ -31,203 +33,203 @@ declare_features! ( // feature-group-start: accepted features // ------------------------------------------------------------------------- - // Allows using associated `type`s in `trait`s. + /// Allows using associated `type`s in `trait`s. (accepted, associated_types, "1.0.0", None, None), - // Allows using assigning a default type to type parameters in algebraic data type definitions. + /// Allows using assigning a default type to type parameters in algebraic data type definitions. (accepted, default_type_params, "1.0.0", None, None), // FIXME: explain `globs`. (accepted, globs, "1.0.0", None, None), - // Allows `macro_rules!` items. + /// Allows `macro_rules!` items. (accepted, macro_rules, "1.0.0", None, None), - // Allows use of `&foo[a..b]` as a slicing syntax. + /// Allows use of `&foo[a..b]` as a slicing syntax. (accepted, slicing_syntax, "1.0.0", None, None), - // Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). + /// Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). (accepted, struct_variant, "1.0.0", None, None), - // Allows indexing tuples. + /// Allows indexing tuples. (accepted, tuple_indexing, "1.0.0", None, None), - // Allows the use of `if let` expressions. + /// Allows the use of `if let` expressions. (accepted, if_let, "1.0.0", None, None), - // Allows the use of `while let` expressions. + /// Allows the use of `while let` expressions. (accepted, while_let, "1.0.0", None, None), - // Allows using `#![no_std]`. + /// Allows using `#![no_std]`. (accepted, no_std, "1.6.0", None, None), - // Allows overloading augmented assignment operations like `a += b`. + /// Allows overloading augmented assignment operations like `a += b`. (accepted, augmented_assignments, "1.8.0", Some(28235), None), - // Allows empty structs and enum variants with braces. + /// Allows empty structs and enum variants with braces. (accepted, braced_empty_structs, "1.8.0", Some(29720), None), - // Allows `#[deprecated]` attribute. + /// Allows `#[deprecated]` attribute. (accepted, deprecated, "1.9.0", Some(29935), None), - // Allows macros to appear in the type position. + /// Allows macros to appear in the type position. (accepted, type_macros, "1.13.0", Some(27245), None), - // Allows use of the postfix `?` operator in expressions. + /// Allows use of the postfix `?` operator in expressions. (accepted, question_mark, "1.13.0", Some(31436), None), - // Allows `..` in tuple (struct) patterns. + /// Allows `..` in tuple (struct) patterns. (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), - // Allows some increased flexibility in the name resolution rules, - // especially around globs and shadowing (RFC 1560). + /// Allows some increased flexibility in the name resolution rules, + /// especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120), None), - // Allows using `Self` and associated types in struct expressions and patterns. + /// Allows using `Self` and associated types in struct expressions and patterns. (accepted, more_struct_aliases, "1.16.0", Some(37544), None), - // Allows elision of `'static` lifetimes in `static`s and `const`s. + /// Allows elision of `'static` lifetimes in `static`s and `const`s. (accepted, static_in_const, "1.17.0", Some(35897), None), - // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. + /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. (accepted, field_init_shorthand, "1.17.0", Some(37340), None), - // Allows the definition recursive static items. + /// Allows the definition recursive static items. (accepted, static_recursion, "1.17.0", Some(29719), None), - // Allows `pub(restricted)` visibilities (RFC 1422). + /// Allows `pub(restricted)` visibilities (RFC 1422). (accepted, pub_restricted, "1.18.0", Some(32409), None), - // Allows `#![windows_subsystem]`. + /// Allows `#![windows_subsystem]`. (accepted, windows_subsystem, "1.18.0", Some(37499), None), - // Allows `break {expr}` with a value inside `loop`s. + /// Allows `break {expr}` with a value inside `loop`s. (accepted, loop_break_value, "1.19.0", Some(37339), None), - // Allows numeric fields in struct expressions and patterns. + /// Allows numeric fields in struct expressions and patterns. (accepted, relaxed_adts, "1.19.0", Some(35626), None), - // Allows coercing non capturing closures to function pointers. + /// Allows coercing non capturing closures to function pointers. (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), - // Allows attributes on struct literal fields. + /// Allows attributes on struct literal fields. (accepted, struct_field_attributes, "1.20.0", Some(38814), None), - // Allows the definition of associated constants in `trait` or `impl` blocks. + /// Allows the definition of associated constants in `trait` or `impl` blocks. (accepted, associated_consts, "1.20.0", Some(29646), None), - // Allows usage of the `compile_error!` macro. + /// Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872), None), - // Allows code like `let x: &'static u32 = &42` to work (RFC 1414). + /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414). (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), - // Allows `Drop` types in constants (RFC 1440). + /// Allows `Drop` types in constants (RFC 1440). (accepted, drop_types_in_const, "1.22.0", Some(33156), None), - // Allows the sysV64 ABI to be specified on all platforms - // instead of just the platforms on which it is the C ABI. + /// Allows the sysV64 ABI to be specified on all platforms + /// instead of just the platforms on which it is the C ABI. (accepted, abi_sysv64, "1.24.0", Some(36167), None), - // Allows `repr(align(16))` struct attribute (RFC 1358). + /// Allows `repr(align(16))` struct attribute (RFC 1358). (accepted, repr_align, "1.25.0", Some(33626), None), - // Allows '|' at beginning of match arms (RFC 1925). + /// Allows '|' at beginning of match arms (RFC 1925). (accepted, match_beginning_vert, "1.25.0", Some(44101), None), - // Allows nested groups in `use` items (RFC 2128). + /// Allows nested groups in `use` items (RFC 2128). (accepted, use_nested_groups, "1.25.0", Some(44494), None), - // Allows indexing into constant arrays. + /// Allows indexing into constant arrays. (accepted, const_indexing, "1.26.0", Some(29947), None), - // Allows using `a..=b` and `..=b` as inclusive range syntaxes. + /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), - // Allows `..=` in patterns (RFC 1192). + /// Allows `..=` in patterns (RFC 1192). (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), - // Allows `fn main()` with return types which implements `Termination` (RFC 1937). + /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301), None), - // Allows implementing `Clone` for closures where possible (RFC 2132). + /// Allows implementing `Clone` for closures where possible (RFC 2132). (accepted, clone_closures, "1.26.0", Some(44490), None), - // Allows implementing `Copy` for closures where possible (RFC 2132). + /// Allows implementing `Copy` for closures where possible (RFC 2132). (accepted, copy_closures, "1.26.0", Some(44490), None), - // Allows `impl Trait` in function arguments. + /// Allows `impl Trait` in function arguments. (accepted, universal_impl_trait, "1.26.0", Some(34511), None), - // Allows `impl Trait` in function return types. + /// Allows `impl Trait` in function return types. (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), - // Allows using the `u128` and `i128` types. + /// Allows using the `u128` and `i128` types. (accepted, i128_type, "1.26.0", Some(35118), None), - // Allows default match binding modes (RFC 2005). + /// Allows default match binding modes (RFC 2005). (accepted, match_default_bindings, "1.26.0", Some(42640), None), - // Allows `'_` placeholder lifetimes. + /// Allows `'_` placeholder lifetimes. (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), - // Allows attributes on lifetime/type formal parameters in generics (RFC 1327). + /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). (accepted, generic_param_attrs, "1.27.0", Some(48848), None), - // Allows `cfg(target_feature = "...")`. + /// Allows `cfg(target_feature = "...")`. (accepted, cfg_target_feature, "1.27.0", Some(29717), None), - // Allows `#[target_feature(...)]`. + /// Allows `#[target_feature(...)]`. (accepted, target_feature, "1.27.0", None, None), - // Allows using `dyn Trait` as a syntax for trait objects. + /// Allows using `dyn Trait` as a syntax for trait objects. (accepted, dyn_trait, "1.27.0", Some(44662), None), - // Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). + /// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). (accepted, fn_must_use, "1.27.0", Some(43302), None), - // Allows use of the `:lifetime` macro fragment specifier. + /// Allows use of the `:lifetime` macro fragment specifier. (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), - // Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). + /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). (accepted, termination_trait_test, "1.27.0", Some(48854), None), - // Allows the `#[global_allocator]` attribute. + /// Allows the `#[global_allocator]` attribute. (accepted, global_allocator, "1.28.0", Some(27389), None), - // Allows `#[repr(transparent)]` attribute on newtype structs. + /// Allows `#[repr(transparent)]` attribute on newtype structs. (accepted, repr_transparent, "1.28.0", Some(43036), None), - // Allows procedural macros in `proc-macro` crates. + /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356), None), - // Allows `foo.rs` as an alternative to `foo/mod.rs`. + /// Allows `foo.rs` as an alternative to `foo/mod.rs`. (accepted, non_modrs_mods, "1.30.0", Some(44660), None), - // Allows use of the `:vis` macro fragment specifier + /// Allows use of the `:vis` macro fragment specifier (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), - // Allows importing and reexporting macros with `use`, - // enables macro modularization in general. + /// Allows importing and reexporting macros with `use`, + /// enables macro modularization in general. (accepted, use_extern_macros, "1.30.0", Some(35896), None), - // Allows keywords to be escaped for use as identifiers. + /// Allows keywords to be escaped for use as identifiers. (accepted, raw_identifiers, "1.30.0", Some(48589), None), - // Allows attributes scoped to tools. + /// Allows attributes scoped to tools. (accepted, tool_attributes, "1.30.0", Some(44690), None), - // Allows multi-segment paths in attributes and derives. + /// Allows multi-segment paths in attributes and derives. (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), - // Allows all literals in attribute lists and values of key-value pairs. + /// Allows all literals in attribute lists and values of key-value pairs. (accepted, attr_literals, "1.30.0", Some(34981), None), - // Allows inferring outlives requirements (RFC 2093). + /// Allows inferring outlives requirements (RFC 2093). (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), - // Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. - // This defines the behavior of panics. + /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. + /// This defines the behavior of panics. (accepted, panic_handler, "1.30.0", Some(44489), None), - // Allows `#[used]` to preserve symbols (see llvm.used). + /// Allows `#[used]` to preserve symbols (see llvm.used). (accepted, used, "1.30.0", Some(40289), None), - // Allows `crate` in paths. + /// Allows `crate` in paths. (accepted, crate_in_paths, "1.30.0", Some(45477), None), - // Allows resolving absolute paths as paths from other crates. + /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), - // Allows access to crate names passed via `--extern` through prelude. + /// Allows access to crate names passed via `--extern` through prelude. (accepted, extern_prelude, "1.30.0", Some(44660), None), - // Allows parentheses in patterns. + /// Allows parentheses in patterns. (accepted, pattern_parentheses, "1.31.0", Some(51087), None), - // Allows the definition of `const fn` functions. + /// Allows the definition of `const fn` functions. (accepted, min_const_fn, "1.31.0", Some(53555), None), - // Allows scoped lints. + /// Allows scoped lints. (accepted, tool_lints, "1.31.0", Some(44690), None), - // Allows lifetime elision in `impl` headers. For example: - // + `impl Iterator for &mut Iterator` - // + `impl Debug for Foo<'_>` + /// Allows lifetime elision in `impl` headers. For example: + /// + `impl Iterator for &mut Iterator` + /// + `impl Debug for Foo<'_>` (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), - // Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. + /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), - // Allows use of the `:literal` macro fragment specifier (RFC 1576). + /// Allows use of the `:literal` macro fragment specifier (RFC 1576). (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), - // Allows use of `?` as the Kleene "at most one" operator in macros. + /// Allows use of `?` as the Kleene "at most one" operator in macros. (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), - // Allows `Self` struct constructor (RFC 2302). + /// Allows `Self` struct constructor (RFC 2302). (accepted, self_struct_ctor, "1.32.0", Some(51994), None), - // Allows `Self` in type definitions (RFC 2300). + /// Allows `Self` in type definitions (RFC 2300). (accepted, self_in_typedefs, "1.32.0", Some(49303), None), - // Allows `use x::y;` to search `x` in the current scope. + /// Allows `use x::y;` to search `x` in the current scope. (accepted, uniform_paths, "1.32.0", Some(53130), None), - // Allows integer match exhaustiveness checking (RFC 2591). + /// Allows integer match exhaustiveness checking (RFC 2591). (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), - // Allows `use path as _;` and `extern crate c as _;`. + /// Allows `use path as _;` and `extern crate c as _;`. (accepted, underscore_imports, "1.33.0", Some(48216), None), - // Allows `#[repr(packed(N))]` attribute on structs. + /// Allows `#[repr(packed(N))]` attribute on structs. (accepted, repr_packed, "1.33.0", Some(33158), None), - // Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). + /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), - // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. + /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), - // Allows let bindings, assignments and destructuring in `const` functions and constants. - // As long as control flow is not implemented in const eval, `&&` and `||` may not be used - // at the same time as let bindings. + /// Allows let bindings, assignments and destructuring in `const` functions and constants. + /// As long as control flow is not implemented in const eval, `&&` and `||` may not be used + /// at the same time as let bindings. (accepted, const_let, "1.33.0", Some(48821), None), - // Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. + /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), - // Allows top level or-patterns (`p | q`) in `if let` and `while let`. + /// Allows top level or-patterns (`p | q`) in `if let` and `while let`. (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), - // Allows `cfg(target_vendor = "...")`. + /// Allows `cfg(target_vendor = "...")`. (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), - // Allows `extern crate self as foo;`. - // This puts local crate root into extern prelude under name `foo`. + /// Allows `extern crate self as foo;`. + /// This puts local crate root into extern prelude under name `foo`. (accepted, extern_crate_self, "1.34.0", Some(56409), None), - // Allows arbitrary delimited token streams in non-macro attributes. + /// Allows arbitrary delimited token streams in non-macro attributes. (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), - // Allows paths to enum variants on type aliases including `Self`. + /// Allows paths to enum variants on type aliases including `Self`. (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), - // Allows using `#[repr(align(X))]` on enums with equivalent semantics - // to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. + /// Allows using `#[repr(align(X))]` on enums with equivalent semantics + /// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. (accepted, repr_align_enum, "1.37.0", Some(57996), None), - // Allows `const _: TYPE = VALUE`. + /// Allows `const _: TYPE = VALUE`. (accepted, underscore_const_names, "1.37.0", Some(54912), None), - // Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. + /// Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. (accepted, async_await, "1.39.0", Some(50547), None), // ------------------------------------------------------------------------- diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 0bff4ed24a4..4008b79b141 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -3,6 +3,7 @@ use crate::edition::Edition; use crate::symbol::{Symbol, sym}; use syntax_pos::Span; +use super::{State, Feature}; macro_rules! set { ($field: ident) => {{ @@ -14,12 +15,24 @@ macro_rules! set { } macro_rules! declare_features { - ($((active, $feature: ident, $ver: expr, $issue: expr, $edition: expr),)+) => { + ($( + $(#[doc = $doc:tt])* (active, $feature:ident, $ver:expr, $issue:expr, $edition:expr), + )+) => { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. pub const ACTIVE_FEATURES: - &[(Symbol, &str, Option, Option, fn(&mut Features, Span))] = - &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+]; + &[Feature] = + &[$( + // (sym::$feature, $ver, $issue, $edition, set!($feature)) + Feature { + state: State::Active { set: set!($feature) }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: $edition, + description: concat!($($doc,)*), + } + ),+]; /// A set of features to be used by later passes. #[derive(Clone)] @@ -28,7 +41,10 @@ macro_rules! declare_features { pub declared_lang_features: Vec<(Symbol, Span, Option)>, /// `#![feature]` attrs for non-language (library) features pub declared_lib_features: Vec<(Symbol, Span)>, - $(pub $feature: bool),+ + $( + $(#[doc = $doc])* + pub $feature: bool + ),+ } impl Features { @@ -58,7 +74,7 @@ macro_rules! declare_features { // stable (active). // // Note that the features are grouped into internal/user-facing and then -// sorted by version inside those groups. This is inforced with tidy. +// sorted by version inside those groups. This is enforced with tidy. // // N.B., `tools/tidy/src/features.rs` parses this information directly out of the // source, so take care when modifying it. @@ -70,127 +86,127 @@ declare_features! ( // no-tracking-issue-start - // Allows using compiler's own crates. + /// Allows using compiler's own crates. (active, rustc_private, "1.0.0", Some(27812), None), - // Allows using the `rust-intrinsic`'s "ABI". + /// Allows using the `rust-intrinsic`'s "ABI". (active, intrinsics, "1.0.0", None, None), - // Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. + /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), - // Allows using the `#[stable]` and `#[unstable]` attributes. + /// Allows using the `#[stable]` and `#[unstable]` attributes. (active, staged_api, "1.0.0", None, None), - // Allows using `#[allow_internal_unstable]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). + /// Allows using `#[allow_internal_unstable]`. This is an + /// attribute on `macro_rules!` and can't use the attribute handling + /// below (it has to be checked before expansion possibly makes + /// macros disappear). (active, allow_internal_unstable, "1.0.0", None, None), - // Allows using `#[allow_internal_unsafe]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). + /// Allows using `#[allow_internal_unsafe]`. This is an + /// attribute on `macro_rules!` and can't use the attribute handling + /// below (it has to be checked before expansion possibly makes + /// macros disappear). (active, allow_internal_unsafe, "1.0.0", None, None), - // Allows using the macros: - // + `__diagnostic_used` - // + `__register_diagnostic` - // +`__build_diagnostic_array` + /// Allows using the macros: + /// + `__diagnostic_used` + /// + `__register_diagnostic` + /// +`__build_diagnostic_array` (active, rustc_diagnostic_macros, "1.0.0", None, None), - // Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which - // lets a function to be `const` when opted into with `#![feature(foo)]`. + /// Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which + /// lets a function to be `const` when opted into with `#![feature(foo)]`. (active, rustc_const_unstable, "1.0.0", None, None), - // no-tracking-issue-end + /// no-tracking-issue-end - // Allows using `#[link_name="llvm.*"]`. + /// Allows using `#[link_name="llvm.*"]`. (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - // Allows using `rustc_*` attributes (RFC 572). + /// Allows using `rustc_*` attributes (RFC 572). (active, rustc_attrs, "1.0.0", Some(29642), None), - // Allows using `#[on_unimplemented(..)]` on traits. + /// Allows using `#[on_unimplemented(..)]` on traits. (active, on_unimplemented, "1.0.0", Some(29628), None), - // Allows using the `box $expr` syntax. + /// Allows using the `box $expr` syntax. (active, box_syntax, "1.0.0", Some(49733), None), - // Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. + /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. (active, main, "1.0.0", Some(29634), None), - // Allows using `#[start]` on a function indicating that it is the program entrypoint. + /// Allows using `#[start]` on a function indicating that it is the program entrypoint. (active, start, "1.0.0", Some(29633), None), - // Allows using the `#[fundamental]` attribute. + /// Allows using the `#[fundamental]` attribute. (active, fundamental, "1.0.0", Some(29635), None), - // Allows using the `rust-call` ABI. + /// Allows using the `rust-call` ABI. (active, unboxed_closures, "1.0.0", Some(29625), None), - // Allows using the `#[linkage = ".."]` attribute. + /// Allows using the `#[linkage = ".."]` attribute. (active, linkage, "1.0.0", Some(29603), None), - // Allows features specific to OIBIT (auto traits). + /// Allows features specific to OIBIT (auto traits). (active, optin_builtin_traits, "1.0.0", Some(13231), None), - // Allows using `box` in patterns (RFC 469). + /// Allows using `box` in patterns (RFC 469). (active, box_patterns, "1.0.0", Some(29641), None), // no-tracking-issue-start - // Allows using `#[prelude_import]` on glob `use` items. + /// Allows using `#[prelude_import]` on glob `use` items. (active, prelude_import, "1.2.0", None, None), // no-tracking-issue-end // no-tracking-issue-start - // Allows using `#[omit_gdb_pretty_printer_section]`. + /// Allows using `#[omit_gdb_pretty_printer_section]`. (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), - // Allows using the `vectorcall` ABI. + /// Allows using the `vectorcall` ABI. (active, abi_vectorcall, "1.7.0", None, None), // no-tracking-issue-end - // Allows using `#[structural_match]` which indicates that a type is structurally matchable. + /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. (active, structural_match, "1.8.0", Some(31434), None), - // Allows using the `may_dangle` attribute (RFC 1327). + /// Allows using the `may_dangle` attribute (RFC 1327). (active, dropck_eyepatch, "1.10.0", Some(34761), None), - // Allows using the `#![panic_runtime]` attribute. + /// Allows using the `#![panic_runtime]` attribute. (active, panic_runtime, "1.10.0", Some(32837), None), - // Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. + /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. (active, needs_panic_runtime, "1.10.0", Some(32837), None), // no-tracking-issue-start - // Allows identifying the `compiler_builtins` crate. + /// Allows identifying the `compiler_builtins` crate. (active, compiler_builtins, "1.13.0", None, None), - // Allows using the `unadjusted` ABI; perma-unstable. + /// Allows using the `unadjusted` ABI; perma-unstable. (active, abi_unadjusted, "1.16.0", None, None), - // Allows identifying crates that contain sanitizer runtimes. + /// Allows identifying crates that contain sanitizer runtimes. (active, sanitizer_runtime, "1.17.0", None, None), - // Used to identify crates that contain the profiler runtime. + /// Used to identify crates that contain the profiler runtime. (active, profiler_runtime, "1.18.0", None, None), - // Allows using the `thiscall` ABI. + /// Allows using the `thiscall` ABI. (active, abi_thiscall, "1.19.0", None, None), - // Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. + /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. (active, allocator_internals, "1.20.0", None, None), // no-tracking-issue-end - // Added for testing E0705; perma-unstable. + /// Added for testing E0705; perma-unstable. (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), // ------------------------------------------------------------------------- @@ -228,281 +244,282 @@ declare_features! ( // feature-group-start: actual feature gates // ------------------------------------------------------------------------- - // Allows using the `#[link_args]` attribute. + /// Allows using the `#[link_args]` attribute. (active, link_args, "1.0.0", Some(29596), None), - // Allows defining identifiers beyond ASCII. + /// Allows defining identifiers beyond ASCII. (active, non_ascii_idents, "1.0.0", Some(55467), None), - // Allows using `#[plugin_registrar]` on functions. + /// Allows using `#[plugin_registrar]` on functions. (active, plugin_registrar, "1.0.0", Some(29597), None), - // Allows using `#![plugin(myplugin)]`. + /// Allows using `#![plugin(myplugin)]`. (active, plugin, "1.0.0", Some(29597), None), - // Allows using `#[thread_local]` on `static` items. + /// Allows using `#[thread_local]` on `static` items. (active, thread_local, "1.0.0", Some(29594), None), - // Allows the use of SIMD types in functions declared in `extern` blocks. + /// Allows the use of SIMD types in functions declared in `extern` blocks. (active, simd_ffi, "1.0.0", Some(27731), None), - // Allows using custom attributes (RFC 572). + /// Allows using custom attributes (RFC 572). (active, custom_attribute, "1.0.0", Some(29642), None), - // Allows using non lexical lifetimes (RFC 2094). + /// Allows using non lexical lifetimes (RFC 2094). (active, nll, "1.0.0", Some(43234), None), - // Allows using slice patterns. + /// Allows using slice patterns. (active, slice_patterns, "1.0.0", Some(62254), None), - // Allows the definition of `const` functions with some advanced features. + /// Allows the definition of `const` functions with some advanced features. (active, const_fn, "1.2.0", Some(57563), None), - // Allows associated type defaults. + /// Allows associated type defaults. (active, associated_type_defaults, "1.2.0", Some(29661), None), - // Allows `#![no_core]`. + /// Allows `#![no_core]`. (active, no_core, "1.3.0", Some(29639), None), - // Allows default type parameters to influence type inference. + /// Allows default type parameters to influence type inference. (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), - // Allows `repr(simd)` and importing the various simd intrinsics. + /// Allows `repr(simd)` and importing the various simd intrinsics. (active, repr_simd, "1.4.0", Some(27731), None), - // Allows `extern "platform-intrinsic" { ... }`. + /// Allows `extern "platform-intrinsic" { ... }`. (active, platform_intrinsics, "1.4.0", Some(27731), None), - // Allows `#[unwind(..)]`. - // - // Permits specifying whether a function should permit unwinding or abort on unwind. + /// Allows `#[unwind(..)]`. + /// + /// Permits specifying whether a function should permit unwinding or abort on unwind. (active, unwind_attributes, "1.4.0", Some(58760), None), - // Allows `#[no_debug]`. + /// Allows `#[no_debug]`. (active, no_debug, "1.5.0", Some(29721), None), - // Allows attributes on expressions and non-item statements. + /// Allows attributes on expressions and non-item statements. (active, stmt_expr_attributes, "1.6.0", Some(15701), None), - // Allows the use of type ascription in expressions. + /// Allows the use of type ascription in expressions. (active, type_ascription, "1.6.0", Some(23416), None), - // Allows `cfg(target_thread_local)`. + /// Allows `cfg(target_thread_local)`. (active, cfg_target_thread_local, "1.7.0", Some(29594), None), - // Allows specialization of implementations (RFC 1210). + /// Allows specialization of implementations (RFC 1210). (active, specialization, "1.7.0", Some(31844), None), - // Allows using `#[naked]` on functions. + /// Allows using `#[naked]` on functions. (active, naked_functions, "1.9.0", Some(32408), None), - // Allows `cfg(target_has_atomic = "...")`. + /// Allows `cfg(target_has_atomic = "...")`. (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - // Allows `X..Y` patterns. + /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - // Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. + /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. (active, never_type, "1.13.0", Some(35121), None), - // Allows exhaustive pattern matching on types that contain uninhabited types. + /// Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", Some(51085), None), - // Allows untagged unions `union U { ... }`. + /// Allows untagged unions `union U { ... }`. (active, untagged_unions, "1.13.0", Some(32836), None), - // Allows `#[link(..., cfg(..))]`. + /// Allows `#[link(..., cfg(..))]`. (active, link_cfg, "1.14.0", Some(37406), None), - // Allows `extern "ptx-*" fn()`. + /// Allows `extern "ptx-*" fn()`. (active, abi_ptx, "1.15.0", Some(38788), None), - // Allows the `#[repr(i128)]` attribute for enums. + /// Allows the `#[repr(i128)]` attribute for enums. (active, repr128, "1.16.0", Some(35118), None), - // Allows `#[link(kind="static-nobundle"...)]`. + /// Allows `#[link(kind="static-nobundle"...)]`. (active, static_nobundle, "1.16.0", Some(37403), None), - // Allows `extern "msp430-interrupt" fn()`. + /// Allows `extern "msp430-interrupt" fn()`. (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), - // Allows declarative macros 2.0 (`macro`). + /// Allows declarative macros 2.0 (`macro`). (active, decl_macro, "1.17.0", Some(39412), None), - // Allows `extern "x86-interrupt" fn()`. + /// Allows `extern "x86-interrupt" fn()`. (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - // Allows overlapping impls of marker traits. + /// Allows overlapping impls of marker traits. (active, overlapping_marker_traits, "1.18.0", Some(29864), None), - // Allows a test to fail without failing the whole suite. + /// Allows a test to fail without failing the whole suite. (active, allow_fail, "1.19.0", Some(46488), None), - // Allows unsized tuple coercion. + /// Allows unsized tuple coercion. (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - // Allows defining generators. + /// Allows defining generators. (active, generators, "1.21.0", Some(43122), None), - // Allows `#[doc(cfg(...))]`. + /// Allows `#[doc(cfg(...))]`. (active, doc_cfg, "1.21.0", Some(43781), None), - // Allows `#[doc(masked)]`. + /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), - // Allows `#[doc(spotlight)]`. + /// Allows `#[doc(spotlight)]`. (active, doc_spotlight, "1.22.0", Some(45040), None), - // Allows `#[doc(include = "some-file")]`. + /// Allows `#[doc(include = "some-file")]`. (active, external_doc, "1.22.0", Some(44732), None), - // Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). + /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). (active, non_exhaustive, "1.22.0", Some(44109), None), - // Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. + /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. (active, crate_visibility_modifier, "1.23.0", Some(53120), None), - // Allows defining `extern type`s. + /// Allows defining `extern type`s. (active, extern_types, "1.23.0", Some(43467), None), - // Allows trait methods with arbitrary self types. + /// Allows trait methods with arbitrary self types. (active, arbitrary_self_types, "1.23.0", Some(44874), None), - // Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). + /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). (active, in_band_lifetimes, "1.23.0", Some(44524), None), - // Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). + /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). (active, generic_associated_types, "1.23.0", Some(44265), None), - // Allows defining `trait X = A + B;` alias items. + /// Allows defining `trait X = A + B;` alias items. (active, trait_alias, "1.24.0", Some(41517), None), - // Allows infering `'static` outlives requirements (RFC 2093). + /// Allows infering `'static` outlives requirements (RFC 2093). (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), - // Allows macro invocations in `extern {}` blocks. + /// Allows macro invocations in `extern {}` blocks. (active, macros_in_extern, "1.27.0", Some(49476), None), - // Allows accessing fields of unions inside `const` functions. + /// Allows accessing fields of unions inside `const` functions. (active, const_fn_union, "1.27.0", Some(51909), None), - // Allows casting raw pointers to `usize` during const eval. + /// Allows casting raw pointers to `usize` during const eval. (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), - // Allows dereferencing raw pointers during const eval. + /// Allows dereferencing raw pointers during const eval. (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - // Allows comparing raw pointers during const eval. + /// Allows comparing raw pointers during const eval. (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), - // Allows `#[doc(alias = "...")]`. + /// Allows `#[doc(alias = "...")]`. (active, doc_alias, "1.27.0", Some(50146), None), - // Allows inconsistent bounds in where clauses. + /// Allows inconsistent bounds in where clauses. (active, trivial_bounds, "1.28.0", Some(48214), None), - // Allows `'a: { break 'a; }`. + /// Allows `'a: { break 'a; }`. (active, label_break_value, "1.28.0", Some(48594), None), - // Allows using `#[doc(keyword = "...")]`. + /// Allows using `#[doc(keyword = "...")]`. (active, doc_keyword, "1.28.0", Some(51315), None), - // Allows reinterpretation of the bits of a value of one type as another type during const eval. + /// Allows reinterpretation of the bits of a value of one type as another + /// type during const eval. (active, const_transmute, "1.29.0", Some(53605), None), - // Allows using `try {...}` expressions. + /// Allows using `try {...}` expressions. (active, try_blocks, "1.29.0", Some(31436), None), - // Allows defining an `#[alloc_error_handler]`. + /// Allows defining an `#[alloc_error_handler]`. (active, alloc_error_handler, "1.29.0", Some(51540), None), - // Allows using the `amdgpu-kernel` ABI. + /// Allows using the `amdgpu-kernel` ABI. (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - // Allows panicking during const eval (producing compile-time errors). + /// Allows panicking during const eval (producing compile-time errors). (active, const_panic, "1.30.0", Some(51999), None), - // Allows `#[marker]` on certain traits allowing overlapping implementations. + /// Allows `#[marker]` on certain traits allowing overlapping implementations. (active, marker_trait_attr, "1.30.0", Some(29864), None), - // Allows macro invocations on modules expressions and statements and - // procedural macros to expand to non-items. + /// Allows macro invocations on modules expressions and statements and + /// procedural macros to expand to non-items. (active, proc_macro_hygiene, "1.30.0", Some(54727), None), - // Allows unsized rvalues at arguments and parameters. + /// Allows unsized rvalues at arguments and parameters. (active, unsized_locals, "1.30.0", Some(48055), None), - // Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. + /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. (active, custom_test_frameworks, "1.30.0", Some(50297), None), - // Allows non-builtin attributes in inner attribute position. + /// Allows non-builtin attributes in inner attribute position. (active, custom_inner_attributes, "1.30.0", Some(54726), None), - // Allows mixing bind-by-move in patterns and references to those identifiers in guards. + /// Allows mixing bind-by-move in patterns and references to those identifiers in guards. (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), - // Allows `impl Trait` in bindings (`let`, `const`, `static`). + /// Allows `impl Trait` in bindings (`let`, `const`, `static`). (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), - // Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. + /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. (active, lint_reasons, "1.31.0", Some(54503), None), - // Allows exhaustive integer pattern matching on `usize` and `isize`. + /// Allows exhaustive integer pattern matching on `usize` and `isize`. (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), - // Allows relaxing the coherence rules such that - // `impl ForeignTrait for ForeignType is permitted. + /// Allows relaxing the coherence rules such that + /// `impl ForeignTrait for ForeignType is permitted. (active, re_rebalance_coherence, "1.32.0", Some(55437), None), - // Allows using `#[ffi_returns_twice]` on foreign functions. + /// Allows using `#[ffi_returns_twice]` on foreign functions. (active, ffi_returns_twice, "1.34.0", Some(58314), None), - // Allows const generic types (e.g. `struct Foo(...);`). + /// Allows const generic types (e.g. `struct Foo(...);`). (active, const_generics, "1.34.0", Some(44580), None), - // Allows using `#[optimize(X)]`. + /// Allows using `#[optimize(X)]`. (active, optimize_attribute, "1.34.0", Some(54882), None), - // Allows using C-variadics. + /// Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), - // Allows the user of associated type bounds. + /// Allows the user of associated type bounds. (active, associated_type_bounds, "1.34.0", Some(52662), None), - // Attributes on formal function params. + /// Attributes on formal function params. (active, param_attrs, "1.36.0", Some(60406), None), - // Allows calling constructor functions in `const fn`. + /// Allows calling constructor functions in `const fn`. (active, const_constructor, "1.37.0", Some(61456), None), - // Allows `if/while p && let q = r && ...` chains. + /// Allows `if/while p && let q = r && ...` chains. (active, let_chains, "1.37.0", Some(53667), None), - // Allows #[repr(transparent)] on enums (RFC 2645). + /// Allows #[repr(transparent)] on enums (RFC 2645). (active, transparent_enums, "1.37.0", Some(60405), None), - // Allows #[repr(transparent)] on unions (RFC 2645). + /// Allows #[repr(transparent)] on unions (RFC 2645). (active, transparent_unions, "1.37.0", Some(60405), None), - // Allows explicit discriminants on non-unit enum variants. + /// Allows explicit discriminants on non-unit enum variants. (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), - // Allows `impl Trait` with multiple unrelated lifetimes. + /// Allows `impl Trait` with multiple unrelated lifetimes. (active, member_constraints, "1.37.0", Some(61977), None), - // Allows `async || body` closures. + /// Allows `async || body` closures. (active, async_closure, "1.37.0", Some(62290), None), - // Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests + /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests (active, cfg_doctest, "1.37.0", Some(62210), None), - // Allows `[x; N]` where `x` is a constant (RFC 2203). + /// Allows `[x; N]` where `x` is a constant (RFC 2203). (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), - // Allows `impl Trait` to be used inside type aliases (RFC 2515). + /// Allows `impl Trait` to be used inside type aliases (RFC 2515). (active, type_alias_impl_trait, "1.38.0", Some(63063), None), - // Allows the use of or-patterns, e.g. `0 | 1`. + /// Allows the use of or-patterns, e.g. `0 | 1`. (active, or_patterns, "1.38.0", Some(54883), None), // ------------------------------------------------------------------------- diff --git a/src/libsyntax/feature_gate/removed.rs b/src/libsyntax/feature_gate/removed.rs index 6ebfeb29f67..6494c82e122 100644 --- a/src/libsyntax/feature_gate/removed.rs +++ b/src/libsyntax/feature_gate/removed.rs @@ -3,14 +3,18 @@ use crate::symbol::{Symbol, sym}; macro_rules! declare_features { - ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { + ($( + $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), + )+) => { /// Represents unstable features which have since been removed (it was once Active) pub const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ $((sym::$feature, $ver, $issue, $reason)),+ ]; }; - ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { + ($( + $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None), + )+) => { /// Represents stable features which have since been removed (it was once Accepted) pub const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ $((sym::$feature, $ver, $issue, None)),+ @@ -25,17 +29,17 @@ declare_features! ( (removed, import_shadowing, "1.0.0", None, None, None), (removed, managed_boxes, "1.0.0", None, None, None), - // Allows use of unary negate on unsigned integers, e.g., -e for e: u8 + /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 (removed, negate_unsigned, "1.0.0", Some(29645), None, None), (removed, reflect, "1.0.0", Some(27749), None, None), - // A way to temporarily opt out of opt in copy. This will *never* be accepted. + /// A way to temporarily opt out of opt in copy. This will *never* be accepted. (removed, opt_out_copy, "1.0.0", None, None, None), (removed, quad_precision_float, "1.0.0", None, None, None), (removed, struct_inherit, "1.0.0", None, None, None), (removed, test_removed_feature, "1.0.0", None, None, None), (removed, visible_private_types, "1.0.0", None, None, None), (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), - // Allows using items which are missing stability attributes + /// Allows using items which are missing stability attributes (removed, unmarked_api, "1.0.0", None, None, None), (removed, allocator, "1.0.0", None, None, None), (removed, simd, "1.0.0", Some(27731), None, @@ -57,18 +61,18 @@ declare_features! ( Some("subsumed by `#![feature(proc_macro_hygiene)]`")), (removed, panic_implementation, "1.28.0", Some(44489), None, Some("subsumed by `#[panic_handler]`")), - // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. + /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. (removed, custom_derive, "1.32.0", Some(29644), None, Some("subsumed by `#[proc_macro_derive]`")), - // Paths of the form: `extern::foo::bar` + /// Paths of the form: `extern::foo::bar` (removed, extern_in_paths, "1.33.0", Some(55600), None, Some("subsumed by `::foo::bar` paths")), (removed, quote, "1.33.0", Some(29601), None, None), - // Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). + /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), (removed, await_macro, "1.38.0", Some(50547), None, Some("subsumed by `.await` syntax")), - // Allows defining `existential type`s. + /// Allows defining `existential type`s. (removed, existential_type, "1.38.0", Some(63063), None, Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), -- cgit 1.4.1-3-g733a5 From 6a3d51731408708cbc6a6e4e2683da8df7326007 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 24 Aug 2019 13:54:40 -0300 Subject: Modifies how Arg, Arm, Field, FieldPattern and Variant are visited Part of the necessary work to accomplish #63468. --- src/librustc/hir/map/def_collector.rs | 7 +- src/librustc/lint/context.rs | 35 ++++----- src/librustc/lint/mod.rs | 36 +++------- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/nonstandard_style.rs | 5 +- src/librustc_passes/ast_validation.rs | 3 +- src/librustc_passes/hir_stats.rs | 7 +- src/libsyntax/ext/expand.rs | 10 ++- src/libsyntax/mut_visit.rs | 126 ++++++++++++++++++++------------- src/libsyntax/util/node_count.rs | 7 +- src/libsyntax/visit.rs | 54 +++++++------- 11 files changed, 147 insertions(+), 145 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index d725afa4052..17bcb1d0859 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -154,7 +154,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { }); } - fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &'a Variant) { let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.as_interned_str()), v.span); @@ -162,12 +162,11 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { if let Some(ctor_hir_id) = v.data.ctor_id() { this.create_def(ctor_hir_id, DefPathData::Ctor, v.span); } - visit::walk_variant(this, v, g, item_id) + visit::walk_variant(this, v) }); } - fn visit_variant_data(&mut self, data: &'a VariantData, _: Ident, - _: &'a Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, data: &'a VariantData) { for (index, field) in data.fields().iter().enumerate() { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| sym::integer(index)); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 6801fa8d8db..8126db14292 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1040,13 +1040,13 @@ for LateContextAndPass<'a, 'tcx, T> { fn visit_variant_data(&mut self, s: &'tcx hir::VariantData, - name: ast::Name, - g: &'tcx hir::Generics, - item_id: hir::HirId, + _: ast::Name, + _: &'tcx hir::Generics, + _: hir::HirId, _: Span) { - lint_callback!(self, check_struct_def, s, name, g, item_id); + lint_callback!(self, check_struct_def, s); hir_visit::walk_struct_def(self, s); - lint_callback!(self, check_struct_def_post, s, name, g, item_id); + lint_callback!(self, check_struct_def_post, s); } fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { @@ -1061,9 +1061,9 @@ for LateContextAndPass<'a, 'tcx, T> { g: &'tcx hir::Generics, item_id: hir::HirId) { self.with_lint_attrs(v.id, &v.attrs, |cx| { - lint_callback!(cx, check_variant, v, g); + lint_callback!(cx, check_variant, v); hir_visit::walk_variant(cx, v, g, item_id); - lint_callback!(cx, check_variant_post, v, g); + lint_callback!(cx, check_variant_post, v); }) } @@ -1214,18 +1214,13 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_fn_post, fk, decl, span, id); } - fn visit_variant_data(&mut self, - s: &'a ast::VariantData, - ident: ast::Ident, - g: &'a ast::Generics, - item_id: ast::NodeId, - _: Span) { - run_early_pass!(self, check_struct_def, s, ident, g, item_id); + fn visit_variant_data(&mut self, s: &'a ast::VariantData) { + run_early_pass!(self, check_struct_def, s); if let Some(ctor_hir_id) = s.ctor_id() { self.check_id(ctor_hir_id); } ast_visit::walk_struct_def(self, s); - run_early_pass!(self, check_struct_def_post, s, ident, g, item_id); + run_early_pass!(self, check_struct_def_post, s); } fn visit_struct_field(&mut self, s: &'a ast::StructField) { @@ -1235,11 +1230,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }) } - fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) { - self.with_lint_attrs(item_id, &v.attrs, |cx| { - run_early_pass!(cx, check_variant, v, g); - ast_visit::walk_variant(cx, v, g, item_id); - run_early_pass!(cx, check_variant_post, v, g); + fn visit_variant(&mut self, v: &'a ast::Variant) { + self.with_lint_attrs(v.id, &v.attrs, |cx| { + run_early_pass!(cx, check_variant, v); + ast_visit::walk_variant(cx, v); + run_early_pass!(cx, check_variant_post, v); }) } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 2b58627cdea..7e2707b98d5 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -248,21 +248,11 @@ macro_rules! late_lint_methods { fn check_trait_item_post(a: &$hir hir::TraitItem); fn check_impl_item(a: &$hir hir::ImplItem); fn check_impl_item_post(a: &$hir hir::ImplItem); - fn check_struct_def( - a: &$hir hir::VariantData, - b: ast::Name, - c: &$hir hir::Generics, - d: hir::HirId - ); - fn check_struct_def_post( - a: &$hir hir::VariantData, - b: ast::Name, - c: &$hir hir::Generics, - d: hir::HirId - ); + fn check_struct_def(a: &$hir hir::VariantData); + fn check_struct_def_post(a: &$hir hir::VariantData); fn check_struct_field(a: &$hir hir::StructField); - fn check_variant(a: &$hir hir::Variant, b: &$hir hir::Generics); - fn check_variant_post(a: &$hir hir::Variant, b: &$hir hir::Generics); + fn check_variant(a: &$hir hir::Variant); + fn check_variant_post(a: &$hir hir::Variant); fn check_lifetime(a: &$hir hir::Lifetime); fn check_path(a: &$hir hir::Path, b: hir::HirId); fn check_attribute(a: &$hir ast::Attribute); @@ -395,21 +385,11 @@ macro_rules! early_lint_methods { fn check_trait_item_post(a: &ast::TraitItem); fn check_impl_item(a: &ast::ImplItem); fn check_impl_item_post(a: &ast::ImplItem); - fn check_struct_def( - a: &ast::VariantData, - b: ast::Ident, - c: &ast::Generics, - d: ast::NodeId - ); - fn check_struct_def_post( - a: &ast::VariantData, - b: ast::Ident, - c: &ast::Generics, - d: ast::NodeId - ); + fn check_struct_def(a: &ast::VariantData); + fn check_struct_def_post(a: &ast::VariantData); fn check_struct_field(a: &ast::StructField); - fn check_variant(a: &ast::Variant, b: &ast::Generics); - fn check_variant_post(a: &ast::Variant, b: &ast::Generics); + fn check_variant(a: &ast::Variant); + fn check_variant_post(a: &ast::Variant); fn check_lifetime(a: &ast::Lifetime); fn check_path(a: &ast::Path, b: ast::NodeId); fn check_attribute(a: &ast::Attribute); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ce7681c974a..d3c94060e27 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -482,7 +482,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } } - fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) { + fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant) { self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index acd17f76632..bb6119d0ff2 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -146,7 +146,7 @@ impl EarlyLintPass for NonCamelCaseTypes { } } - fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant, _: &ast::Generics) { + fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) { self.check_case(cx, "variant", &v.ident); } @@ -350,9 +350,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { &mut self, cx: &LateContext<'_, '_>, s: &hir::VariantData, - _: ast::Name, - _: &hir::Generics, - _: hir::HirId, ) { for sf in s.fields() { self.check_snake_case(cx, "structure field", &sf.ident); diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index bd46ca4779a..5b78727fdd5 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -813,8 +813,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_poly_trait_ref(self, t, m); } - fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident, - _: &'a Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'a VariantData) { self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 8fba3256ec4..7e03df5b75b 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -334,12 +334,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_struct_field(self, s) } - fn visit_variant(&mut self, - v: &'v ast::Variant, - g: &'v ast::Generics, - item_id: NodeId) { + fn visit_variant(&mut self, v: &'v ast::Variant) { self.record("Variant", Id::None, v); - ast_visit::walk_variant(self, v, g, item_id) + ast_visit::walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 72f2c1375e7..92b48ed62cd 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1210,9 +1210,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - fn visit_generic_params(&mut self, params: &mut Vec) { - self.cfg.configure_generic_params(params); - noop_visit_generic_params(params, self); + fn flat_map_generic_param( + &mut self, + param: ast::GenericParam + ) -> SmallVec<[ast::GenericParam; 1]> + { + let param = configure!(self, param); + noop_flat_map_generic_param(param, self) } fn visit_attribute(&mut self, at: &mut ast::Attribute) { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 9785f8e2de0..414d234e434 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -98,8 +98,8 @@ pub trait MutVisitor: Sized { noop_visit_fn_header(header, self); } - fn visit_struct_field(&mut self, sf: &mut StructField) { - noop_visit_struct_field(sf, self); + fn flat_map_struct_field(&mut self, sf: StructField) -> SmallVec<[StructField; 1]> { + noop_flat_map_struct_field(sf, self) } fn visit_item_kind(&mut self, i: &mut ItemKind) { @@ -130,8 +130,8 @@ pub trait MutVisitor: Sized { noop_flat_map_stmt(s, self) } - fn visit_arm(&mut self, a: &mut Arm) { - noop_visit_arm(a, self); + fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { + noop_flat_map_arm(arm, self) } fn visit_pat(&mut self, p: &mut P) { @@ -174,8 +174,8 @@ pub trait MutVisitor: Sized { noop_visit_foreign_mod(nm, self); } - fn visit_variant(&mut self, v: &mut Variant) { - noop_visit_variant(v, self); + fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { + noop_flat_map_variant(v, self) } fn visit_ident(&mut self, i: &mut Ident) { @@ -225,8 +225,8 @@ pub trait MutVisitor: Sized { noop_visit_attribute(at, self); } - fn visit_arg(&mut self, a: &mut Arg) { - noop_visit_arg(a, self); + fn flat_map_arg(&mut self, arg: Arg) -> SmallVec<[Arg; 1]> { + noop_flat_map_arg(arg, self) } fn visit_generics(&mut self, generics: &mut Generics) { @@ -245,12 +245,8 @@ pub trait MutVisitor: Sized { noop_visit_variant_data(vdata, self); } - fn visit_generic_param(&mut self, param: &mut GenericParam) { - noop_visit_generic_param(param, self); - } - - fn visit_generic_params(&mut self, params: &mut Vec) { - noop_visit_generic_params(params, self); + fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { + noop_flat_map_generic_param(param, self) } fn visit_tt(&mut self, tt: &mut TokenTree) { @@ -277,8 +273,8 @@ pub trait MutVisitor: Sized { noop_visit_mt(mt, self); } - fn visit_field(&mut self, field: &mut Field) { - noop_visit_field(field, self); + fn flat_map_field(&mut self, f: Field) -> SmallVec<[Field; 1]> { + noop_flat_map_field(f, self) } fn visit_where_clause(&mut self, where_clause: &mut WhereClause) { @@ -300,6 +296,10 @@ pub trait MutVisitor: Sized { fn visit_span(&mut self, _sp: &mut Span) { // Do nothing. } + + fn flat_map_field_pattern(&mut self, fp: FieldPat) -> SmallVec<[FieldPat; 1]> { + noop_flat_map_field_pattern(fp, self) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -362,6 +362,26 @@ pub fn visit_method_sig(MethodSig { header, decl }: &mut MethodSi vis.visit_fn_decl(decl); } +pub fn noop_flat_map_field_pattern( + mut fp: FieldPat, + vis: &mut T, +) -> SmallVec<[FieldPat; 1]> { + let FieldPat { + attrs, + id, + ident, + is_shorthand: _, + pat, + span, + } = &mut fp; + vis.visit_id(id); + vis.visit_ident(ident); + vis.visit_pat(pat); + vis.visit_span(span); + visit_thin_attrs(attrs, vis); + smallvec![fp] +} + pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { let UseTree { prefix, kind, span } = use_tree; vis.visit_path(prefix); @@ -382,16 +402,18 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arm( - Arm { attrs, pats, guard, body, span, id }: &mut Arm, +pub fn noop_flat_map_arm( + mut arm: Arm, vis: &mut T, -) { +) -> SmallVec<[Arm; 1]> { + let Arm { attrs, pats, guard, body, span, id } = &mut arm; visit_attrs(attrs, vis); vis.visit_id(id); visit_vec(pats, |pat| vis.visit_pat(pat)); visit_opt(guard, |guard| vis.visit_expr(guard)); vis.visit_expr(body); vis.visit_span(span); + smallvec![arm] } pub fn noop_visit_ty_constraint( @@ -425,7 +447,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } TyKind::BareFn(bft) => { let BareFnTy { unsafety: _, abi: _, generic_params, decl } = bft.deref_mut(); - vis.visit_generic_params(generic_params); + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); } TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)), @@ -455,14 +477,17 @@ pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } -pub fn noop_visit_variant(variant: &mut Variant, vis: &mut T) { - let Variant { ident, attrs, id, data, disr_expr, span } = variant; +pub fn noop_flat_map_variant(mut variant: Variant, vis: &mut T) + -> SmallVec<[Variant; 1]> +{ + let Variant { ident, attrs, id, data, disr_expr, span } = &mut variant; vis.visit_ident(ident); visit_attrs(attrs, vis); vis.visit_id(id); vis.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr)); vis.visit_span(span); + smallvec![variant] } pub fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: &mut T) { @@ -562,12 +587,14 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { attrs, id, pat, span, ty }: &mut Arg, vis: &mut T) { +pub fn noop_flat_map_arg(mut arg: Arg, vis: &mut T) -> SmallVec<[Arg; 1]> { + let Arg { attrs, id, pat, span, ty } = &mut arg; vis.visit_id(id); visit_thin_attrs(attrs, vis); vis.visit_pat(pat); vis.visit_span(span); vis.visit_ty(ty); + smallvec![arg] } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { @@ -693,7 +720,7 @@ pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) pub fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { let FnDecl { inputs, output, c_variadic: _ } = decl.deref_mut(); - visit_vec(inputs, |input| vis.visit_arg(input)); + inputs.flat_map_in_place(|arg| vis.flat_map_arg(arg)); match output { FunctionRetTy::Default(span) => vis.visit_span(span), FunctionRetTy::Ty(ty) => vis.visit_ty(ty), @@ -707,8 +734,12 @@ pub fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T) } } -pub fn noop_visit_generic_param(param: &mut GenericParam, vis: &mut T) { - let GenericParam { id, ident, attrs, bounds, kind } = param; +pub fn noop_flat_map_generic_param( + mut param: GenericParam, + vis: &mut T +) -> SmallVec<[GenericParam; 1]> +{ + let GenericParam { id, ident, attrs, bounds, kind } = &mut param; vis.visit_id(id); vis.visit_ident(ident); visit_thin_attrs(attrs, vis); @@ -722,10 +753,7 @@ pub fn noop_visit_generic_param(param: &mut GenericParam, vis: &m vis.visit_ty(ty); } } -} - -pub fn noop_visit_generic_params(params: &mut Vec, vis: &mut T){ - visit_vec(params, |param| vis.visit_generic_param(param)); + smallvec![param] } pub fn noop_visit_label(Label { ident }: &mut Label, vis: &mut T) { @@ -739,7 +767,7 @@ fn noop_visit_lifetime(Lifetime { id, ident }: &mut Lifetime, vis pub fn noop_visit_generics(generics: &mut Generics, vis: &mut T) { let Generics { params, where_clause, span } = generics; - vis.visit_generic_params(params); + params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_where_clause(where_clause); vis.visit_span(span); } @@ -755,7 +783,7 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: WherePredicate::BoundPredicate(bp) => { let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; vis.visit_span(span); - vis.visit_generic_params(bound_generic_params); + bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_ty(bounded_ty); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } @@ -777,9 +805,11 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) { match vdata { - VariantData::Struct(fields, ..) => visit_vec(fields, |field| vis.visit_struct_field(field)), + VariantData::Struct(fields, ..) => { + fields.flat_map_in_place(|field| vis.flat_map_struct_field(field)); + }, VariantData::Tuple(fields, id) => { - visit_vec(fields, |field| vis.visit_struct_field(field)); + fields.flat_map_in_place(|field| vis.flat_map_struct_field(field)); vis.visit_id(id); }, VariantData::Unit(id) => vis.visit_id(id), @@ -793,28 +823,32 @@ pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut Trait pub fn noop_visit_poly_trait_ref(p: &mut PolyTraitRef, vis: &mut T) { let PolyTraitRef { bound_generic_params, trait_ref, span } = p; - vis.visit_generic_params(bound_generic_params); + bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_trait_ref(trait_ref); vis.visit_span(span); } -pub fn noop_visit_struct_field(f: &mut StructField, visitor: &mut T) { - let StructField { span, ident, vis, id, ty, attrs } = f; +pub fn noop_flat_map_struct_field(mut sf: StructField, visitor: &mut T) + -> SmallVec<[StructField; 1]> +{ + let StructField { span, ident, vis, id, ty, attrs } = &mut sf; visitor.visit_span(span); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_vis(vis); visitor.visit_id(id); visitor.visit_ty(ty); visit_attrs(attrs, visitor); + smallvec![sf] } -pub fn noop_visit_field(f: &mut Field, vis: &mut T) { - let Field { ident, expr, span, is_shorthand: _, attrs, id } = f; +pub fn noop_flat_map_field(mut f: Field, vis: &mut T) -> SmallVec<[Field; 1]> { + let Field { ident, expr, span, is_shorthand: _, attrs, id } = &mut f; vis.visit_ident(ident); vis.visit_expr(expr); vis.visit_id(id); vis.visit_span(span); visit_thin_attrs(attrs, vis); + smallvec![f] } pub fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) { @@ -858,7 +892,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_generics(generics); } ItemKind::Enum(EnumDef { variants }, generics) => { - visit_vec(variants, |variant| vis.visit_variant(variant)); + variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); vis.visit_generics(generics); } ItemKind::Struct(variant_data, generics) | @@ -1042,13 +1076,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { } PatKind::Struct(path, fields, _etc) => { vis.visit_path(path); - for FieldPat { ident, pat, is_shorthand: _, attrs, id, span } in fields { - vis.visit_ident(ident); - vis.visit_id(id); - vis.visit_pat(pat); - visit_thin_attrs(attrs, vis); - vis.visit_span(span); - }; + fields.flat_map_in_place(|field| vis.flat_map_field_pattern(field)); } PatKind::Box(inner) => vis.visit_pat(inner), PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), @@ -1130,7 +1158,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, } ExprKind::Match(expr, arms) => { vis.visit_expr(expr); - visit_vec(arms, |arm| vis.visit_arm(arm)); + arms.flat_map_in_place(|arm| vis.flat_map_arm(arm)); } ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => { vis.visit_asyncness(asyncness); @@ -1193,7 +1221,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, ExprKind::Mac(mac) => vis.visit_mac(mac), ExprKind::Struct(path, fields, expr) => { vis.visit_path(path); - visit_vec(fields, |field| vis.visit_field(field)); + fields.flat_map_in_place(|field| vis.flat_map_field(field)); visit_opt(expr, |expr| vis.visit_expr(expr)); }, ExprKind::Paren(expr) => { diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index f17eb3b3943..a64fec70961 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -93,8 +93,7 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &VariantData, _: Ident, - _: &Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &VariantData) { self.count += 1; walk_struct_def(self, s) } @@ -107,9 +106,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &Variant) { self.count += 1; - walk_variant(self, v, g, item_id) + walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &Lifetime) { self.count += 1; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 91b92d84a81..86f6d36c3c6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -92,8 +92,7 @@ pub trait Visitor<'ast>: Sized { fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &'ast VariantData, _: Ident, - _: &'ast Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'ast VariantData) { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'ast StructField) { walk_struct_field(self, s) } @@ -101,8 +100,8 @@ pub trait Visitor<'ast>: Sized { generics: &'ast Generics, item_id: NodeId, _: Span) { walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) { - walk_variant(self, v, g, item_id) + fn visit_variant(&mut self, v: &'ast Variant) { + walk_variant(self, v) } fn visit_label(&mut self, label: &'ast Label) { walk_label(self, label) @@ -163,6 +162,12 @@ pub trait Visitor<'ast>: Sized { fn visit_fn_header(&mut self, _header: &'ast FnHeader) { // Nothing to do } + fn visit_field(&mut self, f: &'ast Field) { + walk_field(self, f) + } + fn visit_field_pattern(&mut self, fp: &'ast FieldPat) { + walk_field_pattern(self, fp) + } } #[macro_export] @@ -280,8 +285,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_variant_data(struct_definition, item.ident, - generics, item.id, item.span); + visitor.visit_variant_data(struct_definition); } ItemKind::Trait(.., ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); @@ -300,24 +304,32 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef, - generics: &'a Generics, - item_id: NodeId) { - walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id); + _: &'a Generics, + _: NodeId) { + walk_list!(visitor, visit_variant, &enum_definition.variants); } -pub fn walk_variant<'a, V>(visitor: &mut V, - variant: &'a Variant, - generics: &'a Generics, - item_id: NodeId) +pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) where V: Visitor<'a>, { visitor.visit_ident(variant.ident); - visitor.visit_variant_data(&variant.data, variant.ident, - generics, item_id, variant.span); + visitor.visit_variant_data(&variant.data); walk_list!(visitor, visit_anon_const, &variant.disr_expr); walk_list!(visitor, visit_attribute, &variant.attrs); } +pub fn walk_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a Field) { + visitor.visit_expr(&f.expr); + visitor.visit_ident(f.ident); + walk_list!(visitor, visit_attribute, f.attrs.iter()); +} + +pub fn walk_field_pattern<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a FieldPat) { + visitor.visit_ident(fp.ident); + visitor.visit_pat(&fp.pat); + walk_list!(visitor, visit_attribute, fp.attrs.iter()); +} + pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { match typ.node { TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => { @@ -441,11 +453,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } PatKind::Struct(ref path, ref fields, _) => { visitor.visit_path(path, pattern.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.attrs.iter()); - visitor.visit_ident(field.ident); - visitor.visit_pat(&field.pat) - } + walk_list!(visitor, visit_field_pattern, fields); } PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) | @@ -686,11 +694,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { } ExprKind::Struct(ref path, ref fields, ref optional_base) => { visitor.visit_path(path, expression.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.attrs.iter()); - visitor.visit_ident(field.ident); - visitor.visit_expr(&field.expr) - } + walk_list!(visitor, visit_field, fields); walk_list!(visitor, visit_expr, optional_base); } ExprKind::Tup(ref subexpressions) => { -- cgit 1.4.1-3-g733a5 From 5299d8a191246cf55c8ead7b8be68c8aeca78d35 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 15:28:14 +0200 Subject: parser: extract `ban_unexpected_or_or`. --- src/libsyntax/parse/parser/pat.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 8cfa6abbe62..4cda14907e4 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -31,14 +31,7 @@ impl<'a> Parser<'a> { pats.push(self.parse_top_level_pat()?); if self.token == token::OrOr { - self.struct_span_err(self.token.span, "unexpected token `||` after pattern") - .span_suggestion( - self.token.span, - "use a single `|` to specify multiple patterns", - "|".to_owned(), - Applicability::MachineApplicable - ) - .emit(); + self.ban_unexpected_or_or(); self.bump(); } else if self.eat(&token::BinOp(token::Or)) { // This is a No-op. Continue the loop to parse the next @@ -49,6 +42,17 @@ impl<'a> Parser<'a> { }; } + fn ban_unexpected_or_or(&mut self) { + self.struct_span_err(self.token.span, "unexpected token `||` after pattern") + .span_suggestion( + self.token.span, + "use a single `|` to specify multiple patterns", + "|".to_owned(), + Applicability::MachineApplicable + ) + .emit(); + } + /// A wrapper around `parse_pat` with some special error handling for the /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast /// to subpatterns within such). @@ -116,9 +120,7 @@ impl<'a> Parser<'a> { let mut pats = vec![first_pat]; while self.eat(&token::BinOp(token::Or)) { - pats.push(self.parse_pat_with_range_pat( - true, expected - )?); + pats.push(self.parse_pat_with_range_pat(true, expected)?); } let or_pattern_span = lo.to(self.prev_span); -- cgit 1.4.1-3-g733a5 From 1ba7550a8996cffc07c6af89dcd6e1cdc63b24cf Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 15:31:34 +0200 Subject: parser: type alias `type Expected = Option<&'static str>;`. --- src/libsyntax/parse/parser/pat.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 4cda14907e4..36d5ed5c4aa 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -12,12 +12,11 @@ use crate::ThinVec; use errors::{Applicability, DiagnosticBuilder}; +type Expected = Option<&'static str>; + impl<'a> Parser<'a> { /// Parses a pattern. - pub fn parse_pat( - &mut self, - expected: Option<&'static str> - ) -> PResult<'a, P> { + pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P> { self.parse_pat_with_range_pat(true, expected) } @@ -105,7 +104,7 @@ impl<'a> Parser<'a> { } /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). - fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P> { + fn parse_pat_with_or(&mut self, expected: Expected) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; @@ -135,7 +134,7 @@ impl<'a> Parser<'a> { fn parse_pat_with_range_pat( &mut self, allow_range_pat: bool, - expected: Option<&'static str>, + expected: Expected, ) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole!(self, NtPat, |x| x); @@ -257,7 +256,7 @@ impl<'a> Parser<'a> { } /// Parse `&pat` / `&mut pat`. - fn parse_pat_deref(&mut self, expected: Option<&'static str>) -> PResult<'a, PatKind> { + fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> { self.expect_and()?; let mutbl = self.parse_mutability(); @@ -363,7 +362,7 @@ impl<'a> Parser<'a> { fn fatal_unexpected_non_pat( &mut self, mut err: DiagnosticBuilder<'a>, - expected: Option<&'static str>, + expected: Expected, ) -> PResult<'a, P> { self.cancel(&mut err); -- cgit 1.4.1-3-g733a5 From 0bbea47794d28f78cf313fde475a35a83d0e9842 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 15:45:44 +0200 Subject: parser: refactor `parse_pat_with_or` + use it in [p0, p1, ..] pats. --- src/libsyntax/parse/parser/pat.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 36d5ed5c4aa..ca5a9f2a5a8 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -104,12 +104,12 @@ impl<'a> Parser<'a> { } /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). - fn parse_pat_with_or(&mut self, expected: Expected) -> PResult<'a, P> { + fn parse_pat_with_or(&mut self, expected: Expected, gate_or: bool) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; - // If the next token is not a `|`, this is not an or-pattern and - // we should exit here. + // If the next token is not a `|`, + // this is not an or-pattern and we should exit here. if !self.check(&token::BinOp(token::Or)) { return Ok(first_pat) } @@ -124,7 +124,10 @@ impl<'a> Parser<'a> { let or_pattern_span = lo.to(self.prev_span); - self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); + // Feature gate the or-pattern if instructed: + if gate_or { + self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); + } Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } @@ -145,7 +148,11 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Paren) => self.parse_pat_tuple_or_parens()?, token::OpenDelim(token::Bracket) => { // Parse `[pat, pat,...]` as a slice pattern. - PatKind::Slice(self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?.0) + let (pats, _) = self.parse_delim_comma_seq( + token::Bracket, + |p| p.parse_pat_with_or(None, true), + )?; + PatKind::Slice(pats) } token::DotDot => { self.bump(); @@ -273,7 +280,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or(None) + p.parse_pat_with_or(None, true) })?; // Here, `(pat,)` is a tuple pattern. @@ -517,7 +524,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true))?; Ok(PatKind::TupleStruct(path, fields)) } @@ -661,7 +668,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or(None)?; + let pat = self.parse_pat_with_or(None, true)?; hi = pat.span; (pat, fieldname, false) } else { -- cgit 1.4.1-3-g733a5 From 30b841dce0a1c0f26588f4b5791a9eda1c1f42f4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 16:35:19 +0200 Subject: parser: improve or-patterns recovery. --- src/libsyntax/parse/parser/pat.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index ca5a9f2a5a8..e52d0bc9d48 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -110,18 +110,25 @@ impl<'a> Parser<'a> { // If the next token is not a `|`, // this is not an or-pattern and we should exit here. - if !self.check(&token::BinOp(token::Or)) { + if !self.check(&token::BinOp(token::Or)) && self.token != token::OrOr { return Ok(first_pat) } let lo = first_pat.span; - let mut pats = vec![first_pat]; + loop { + if self.token == token::OrOr { + // Found `||`; Recover and pretend we parsed `|`. + self.ban_unexpected_or_or(); + self.bump(); + } else if self.eat(&token::BinOp(token::Or)) { + // Found `|`. Working towards a proper or-pattern. + } else { + break; + } - while self.eat(&token::BinOp(token::Or)) { pats.push(self.parse_pat_with_range_pat(true, expected)?); } - let or_pattern_span = lo.to(self.prev_span); // Feature gate the or-pattern if instructed: -- cgit 1.4.1-3-g733a5 From f852c7ce1c6f55bc816d90c6e7f8e9205bb6c6f2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 16:55:52 +0200 Subject: parser: simplify `parse_pat_with_or`. --- src/libsyntax/parse/parser/pat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index e52d0bc9d48..89688a287a7 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -127,7 +127,7 @@ impl<'a> Parser<'a> { break; } - pats.push(self.parse_pat_with_range_pat(true, expected)?); + pats.push(self.parse_pat(expected)?); } let or_pattern_span = lo.to(self.prev_span); -- cgit 1.4.1-3-g733a5 From 21d9b85c0da1b639f8d8b3585e08759f96d1c286 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 17:11:12 +0200 Subject: parser: extract `maybe_recover_unexpected_comma`. --- src/libsyntax/parse/parser/pat.rs | 67 +++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 31 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 89688a287a7..588e5aef8a2 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -57,40 +57,45 @@ impl<'a> Parser<'a> { /// to subpatterns within such). pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { let pat = self.parse_pat(None)?; - if self.token == token::Comma { - // An unexpected comma after a top-level pattern is a clue that the - // user (perhaps more accustomed to some other language) forgot the - // parentheses in what should have been a tuple pattern; return a - // suggestion-enhanced error here rather than choking on the comma - // later. - let comma_span = self.token.span; - self.bump(); - if let Err(mut err) = self.skip_pat_list() { - // We didn't expect this to work anyway; we just wanted - // to advance to the end of the comma-sequence so we know - // the span to suggest parenthesizing - err.cancel(); - } - let seq_span = pat.span.to(self.prev_span); - let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - err.span_suggestion( - seq_span, - "try adding parentheses to match on a tuple..", - format!("({})", seq_snippet), - Applicability::MachineApplicable - ).span_suggestion( - seq_span, - "..or a vertical bar to match on multiple alternatives", - format!("{}", seq_snippet.replace(",", " |")), - Applicability::MachineApplicable - ); - } - return Err(err); - } + self.maybe_recover_unexpected_comma(pat.span)?; Ok(pat) } + fn maybe_recover_unexpected_comma(&mut self, lo: Span) -> PResult<'a, ()> { + if self.token != token::Comma { + return Ok(()); + } + + // An unexpected comma after a top-level pattern is a clue that the + // user (perhaps more accustomed to some other language) forgot the + // parentheses in what should have been a tuple pattern; return a + // suggestion-enhanced error here rather than choking on the comma later. + let comma_span = self.token.span; + self.bump(); + if let Err(mut err) = self.skip_pat_list() { + // We didn't expect this to work anyway; we just wanted to advance to the + // end of the comma-sequence so we know the span to suggest parenthesizing. + err.cancel(); + } + let seq_span = lo.to(self.prev_span); + let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + err.span_suggestion( + seq_span, + "try adding parentheses to match on a tuple..", + format!("({})", seq_snippet), + Applicability::MachineApplicable + ) + .span_suggestion( + seq_span, + "..or a vertical bar to match on multiple alternatives", + format!("{}", seq_snippet.replace(",", " |")), + Applicability::MachineApplicable + ); + } + Err(err) + } + /// Parse and throw away a parentesized comma separated /// sequence of patterns until `)` is reached. fn skip_pat_list(&mut self) -> PResult<'a, ()> { -- cgit 1.4.1-3-g733a5 From a4a34ab62df777e885cac71ab171225b2cd1a812 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 17:44:27 +0200 Subject: parser: integrate `maybe_recover_unexpected_comma` in `parse_pat_with_or`. --- src/libsyntax/parse/parser/pat.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 588e5aef8a2..b2a026d0071 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -57,12 +57,12 @@ impl<'a> Parser<'a> { /// to subpatterns within such). pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { let pat = self.parse_pat(None)?; - self.maybe_recover_unexpected_comma(pat.span)?; + self.maybe_recover_unexpected_comma(pat.span, true)?; Ok(pat) } - fn maybe_recover_unexpected_comma(&mut self, lo: Span) -> PResult<'a, ()> { - if self.token != token::Comma { + fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: bool) -> PResult<'a, ()> { + if !top_level || self.token != token::Comma { return Ok(()); } @@ -109,9 +109,15 @@ impl<'a> Parser<'a> { } /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). - fn parse_pat_with_or(&mut self, expected: Expected, gate_or: bool) -> PResult<'a, P> { + fn parse_pat_with_or( + &mut self, + expected: Expected, + gate_or: bool, + top_level: bool + ) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; + self.maybe_recover_unexpected_comma(first_pat.span, top_level)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -132,7 +138,9 @@ impl<'a> Parser<'a> { break; } - pats.push(self.parse_pat(expected)?); + let pat = self.parse_pat(expected)?; + self.maybe_recover_unexpected_comma(pat.span, top_level)?; + pats.push(pat); } let or_pattern_span = lo.to(self.prev_span); @@ -162,7 +170,7 @@ impl<'a> Parser<'a> { // Parse `[pat, pat,...]` as a slice pattern. let (pats, _) = self.parse_delim_comma_seq( token::Bracket, - |p| p.parse_pat_with_or(None, true), + |p| p.parse_pat_with_or(None, true, false), )?; PatKind::Slice(pats) } @@ -292,7 +300,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or(None, true) + p.parse_pat_with_or(None, true, false) })?; // Here, `(pat,)` is a tuple pattern. @@ -536,7 +544,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true, false))?; Ok(PatKind::TupleStruct(path, fields)) } @@ -680,7 +688,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or(None, true)?; + let pat = self.parse_pat_with_or(None, true, false)?; hi = pat.span; (pat, fieldname, false) } else { -- cgit 1.4.1-3-g733a5 From 7b59b4f14dae8c859718d60794021230e1e3ac29 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:13:19 +0200 Subject: parser: extract `eat_or_separator`. --- src/libsyntax/parse/parser/pat.rs | 58 +++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 30 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index b2a026d0071..3af64cef74f 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -29,27 +29,10 @@ impl<'a> Parser<'a> { loop { pats.push(self.parse_top_level_pat()?); - if self.token == token::OrOr { - self.ban_unexpected_or_or(); - self.bump(); - } else if self.eat(&token::BinOp(token::Or)) { - // This is a No-op. Continue the loop to parse the next - // pattern. - } else { + if !self.eat_or_separator() { return Ok(pats); } - }; - } - - fn ban_unexpected_or_or(&mut self) { - self.struct_span_err(self.token.span, "unexpected token `||` after pattern") - .span_suggestion( - self.token.span, - "use a single `|` to specify multiple patterns", - "|".to_owned(), - Applicability::MachineApplicable - ) - .emit(); + } } /// A wrapper around `parse_pat` with some special error handling for the @@ -127,17 +110,7 @@ impl<'a> Parser<'a> { let lo = first_pat.span; let mut pats = vec![first_pat]; - loop { - if self.token == token::OrOr { - // Found `||`; Recover and pretend we parsed `|`. - self.ban_unexpected_or_or(); - self.bump(); - } else if self.eat(&token::BinOp(token::Or)) { - // Found `|`. Working towards a proper or-pattern. - } else { - break; - } - + while self.eat_or_separator() { let pat = self.parse_pat(expected)?; self.maybe_recover_unexpected_comma(pat.span, top_level)?; pats.push(pat); @@ -152,6 +125,31 @@ impl<'a> Parser<'a> { Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } + /// Eat the or-pattern `|` separator. + /// If instead a `||` token is encountered, recover and pretend we parsed `|`. + fn eat_or_separator(&mut self) -> bool { + match self.token.kind { + token::OrOr => { + // Found `||`; Recover and pretend we parsed `|`. + self.ban_unexpected_or_or(); + self.bump(); + true + } + _ => self.eat(&token::BinOp(token::Or)), + } + } + + fn ban_unexpected_or_or(&mut self) { + self.struct_span_err(self.token.span, "unexpected token `||` after pattern") + .span_suggestion( + self.token.span, + "use a single `|` to specify multiple patterns", + "|".to_owned(), + Applicability::MachineApplicable + ) + .emit(); + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( -- cgit 1.4.1-3-g733a5 From dc5bbaf7b2df8dc2be6c0f1a9973867e5519300b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:15:17 +0200 Subject: parser: improve `parse_pat_with_or` docs. --- src/libsyntax/parse/parser/pat.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 3af64cef74f..14ac509d6f7 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -91,7 +91,8 @@ impl<'a> Parser<'a> { Ok(()) } - /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). + /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). + /// Corresponds to `pat` in RFC 2535. fn parse_pat_with_or( &mut self, expected: Expected, -- cgit 1.4.1-3-g733a5 From 6498959377421876040515af39b6491a2ec2a0c5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:34:35 +0200 Subject: parser: use `eat_or_separator` for leading vert. --- src/libsyntax/parse/parser/pat.rs | 4 ++-- src/test/ui/or-patterns/multiple-pattern-typo.rs | 5 +++++ src/test/ui/or-patterns/multiple-pattern-typo.stderr | 8 +++++++- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 14ac509d6f7..1063e347530 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -22,8 +22,8 @@ impl<'a> Parser<'a> { /// Parses patterns, separated by '|' s. pub(super) fn parse_pats(&mut self) -> PResult<'a, Vec>> { - // Allow a '|' before the pats (RFC 1925 + RFC 2530) - self.eat(&token::BinOp(token::Or)); + // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). + self.eat_or_separator(); let mut pats = Vec::new(); loop { diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs index 5d1da56674b..e308c0adb4e 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.rs +++ b/src/test/ui/or-patterns/multiple-pattern-typo.rs @@ -37,4 +37,9 @@ fn main() { [1 | 2 || 3] => (), //~ ERROR unexpected token `||` after pattern _ => (), } + + match x { + || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } } diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index 97f3470a54a..765c7879b12 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -34,6 +34,12 @@ error: unexpected token `||` after pattern LL | [1 | 2 || 3] => (), | ^^ help: use a single `|` to specify multiple patterns: `|` +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:42:9 + | +LL | || 1 | 2 | 3 => (), + | ^^ help: use a single `|` to specify multiple patterns: `|` + warning: the feature `or_patterns` is incomplete and may cause the compiler to crash --> $DIR/multiple-pattern-typo.rs:1:12 | @@ -42,5 +48,5 @@ LL | #![feature(or_patterns)] | = note: `#[warn(incomplete_features)]` on by default -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 39f5e5bec42a4c05588db45d12ab9aafc01776aa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:37:41 +0200 Subject: parser: move `maybe_recover_unexpected_comma` to a more appropriate place. --- src/libsyntax/parse/parser/pat.rs | 99 +++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 50 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 1063e347530..680a5872056 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -35,62 +35,12 @@ impl<'a> Parser<'a> { } } - /// A wrapper around `parse_pat` with some special error handling for the - /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast - /// to subpatterns within such). pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { let pat = self.parse_pat(None)?; self.maybe_recover_unexpected_comma(pat.span, true)?; Ok(pat) } - fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: bool) -> PResult<'a, ()> { - if !top_level || self.token != token::Comma { - return Ok(()); - } - - // An unexpected comma after a top-level pattern is a clue that the - // user (perhaps more accustomed to some other language) forgot the - // parentheses in what should have been a tuple pattern; return a - // suggestion-enhanced error here rather than choking on the comma later. - let comma_span = self.token.span; - self.bump(); - if let Err(mut err) = self.skip_pat_list() { - // We didn't expect this to work anyway; we just wanted to advance to the - // end of the comma-sequence so we know the span to suggest parenthesizing. - err.cancel(); - } - let seq_span = lo.to(self.prev_span); - let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - err.span_suggestion( - seq_span, - "try adding parentheses to match on a tuple..", - format!("({})", seq_snippet), - Applicability::MachineApplicable - ) - .span_suggestion( - seq_span, - "..or a vertical bar to match on multiple alternatives", - format!("{}", seq_snippet.replace(",", " |")), - Applicability::MachineApplicable - ); - } - Err(err) - } - - /// Parse and throw away a parentesized comma separated - /// sequence of patterns until `)` is reached. - fn skip_pat_list(&mut self) -> PResult<'a, ()> { - while !self.check(&token::CloseDelim(token::Paren)) { - self.parse_pat(None)?; - if !self.eat(&token::Comma) { - return Ok(()) - } - } - Ok(()) - } - /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). /// Corresponds to `pat` in RFC 2535. fn parse_pat_with_or( @@ -151,6 +101,55 @@ impl<'a> Parser<'a> { .emit(); } + /// Some special error handling for the "top-level" patterns in a match arm, + /// `for` loop, `let`, &c. (in contrast to subpatterns within such). + fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: bool) -> PResult<'a, ()> { + if !top_level || self.token != token::Comma { + return Ok(()); + } + + // An unexpected comma after a top-level pattern is a clue that the + // user (perhaps more accustomed to some other language) forgot the + // parentheses in what should have been a tuple pattern; return a + // suggestion-enhanced error here rather than choking on the comma later. + let comma_span = self.token.span; + self.bump(); + if let Err(mut err) = self.skip_pat_list() { + // We didn't expect this to work anyway; we just wanted to advance to the + // end of the comma-sequence so we know the span to suggest parenthesizing. + err.cancel(); + } + let seq_span = lo.to(self.prev_span); + let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + err.span_suggestion( + seq_span, + "try adding parentheses to match on a tuple..", + format!("({})", seq_snippet), + Applicability::MachineApplicable + ) + .span_suggestion( + seq_span, + "..or a vertical bar to match on multiple alternatives", + format!("{}", seq_snippet.replace(",", " |")), + Applicability::MachineApplicable + ); + } + Err(err) + } + + /// Parse and throw away a parentesized comma separated + /// sequence of patterns until `)` is reached. + fn skip_pat_list(&mut self) -> PResult<'a, ()> { + while !self.check(&token::CloseDelim(token::Paren)) { + self.parse_pat(None)?; + if !self.eat(&token::Comma) { + return Ok(()) + } + } + Ok(()) + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( -- cgit 1.4.1-3-g733a5 From 8f6a0cdb0fd453580bed74586c6930b1498aa26f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 18:38:36 +0200 Subject: parser: document `ban_unexpected_or_or`. --- src/libsyntax/parse/parser/pat.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 680a5872056..8fab8884ca0 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -90,6 +90,7 @@ impl<'a> Parser<'a> { } } + /// We have parsed `||` instead of `|`. Error and suggest `|` instead. fn ban_unexpected_or_or(&mut self) { self.struct_span_err(self.token.span, "unexpected token `||` after pattern") .span_suggestion( -- cgit 1.4.1-3-g733a5 From b7178ef9836fe8e98ffb3f8d4d870c94e6fe816d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 22:04:28 +0200 Subject: parser: `parse_pats` -> `parse_top_pat{_unpack}`. --- src/libsyntax/parse/parser/expr.rs | 12 +++++++----- src/libsyntax/parse/parser/pat.rs | 28 +++++++++++++++++----------- 2 files changed, 24 insertions(+), 16 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 5da9b75d53b..b9dd8518171 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1241,11 +1241,12 @@ impl<'a> Parser<'a> { Ok(cond) } - /// Parses a `let $pats = $expr` pseudo-expression. + /// Parses a `let $pat = $expr` pseudo-expression. /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; - let pats = self.parse_pats()?; + // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. + let pat = self.parse_top_pat_unpack(false)?; self.expect(&token::Eq)?; let expr = self.with_res( Restrictions::NO_STRUCT_LITERAL, @@ -1253,7 +1254,7 @@ impl<'a> Parser<'a> { )?; let span = lo.to(expr.span); self.sess.gated_spans.let_chains.borrow_mut().push(span); - Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs)) + Ok(self.mk_expr(span, ExprKind::Let(pat, expr), attrs)) } /// `else` token already eaten @@ -1387,7 +1388,8 @@ impl<'a> Parser<'a> { crate fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - let pats = self.parse_pats()?; + // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. + let pat = self.parse_top_pat_unpack(false)?; let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { @@ -1448,7 +1450,7 @@ impl<'a> Parser<'a> { Ok(ast::Arm { attrs, - pats, + pats: pat, // FIXME(or_patterns, Centril | dlrobertson): this should just be `pat,`. guard, body: expr, span: lo.to(hi), diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 8fab8884ca0..e4a9dc00977 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -20,19 +20,25 @@ impl<'a> Parser<'a> { self.parse_pat_with_range_pat(true, expected) } - /// Parses patterns, separated by '|' s. - pub(super) fn parse_pats(&mut self) -> PResult<'a, Vec>> { - // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - self.eat_or_separator(); - - let mut pats = Vec::new(); - loop { - pats.push(self.parse_top_level_pat()?); + // FIXME(or_patterns, Centril | dlrobertson): + // remove this and use `parse_top_pat` everywhere it is used instead. + pub(super) fn parse_top_pat_unpack(&mut self, gate_or: bool) -> PResult<'a, Vec>> { + self.parse_top_pat(gate_or) + .map(|pat| pat.and_then(|pat| match pat.node { + PatKind::Or(pats) => pats, + node => vec![self.mk_pat(pat.span, node)], + })) + } - if !self.eat_or_separator() { - return Ok(pats); - } + /// Entry point to the main pattern parser. + /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. + pub(super) fn parse_top_pat(&mut self, gate_or: bool) -> PResult<'a, P> { + // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). + if self.eat_or_separator() && gate_or { + self.sess.gated_spans.or_patterns.borrow_mut().push(self.prev_span); } + + self.parse_pat_with_or(None, gate_or, true) } pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { -- cgit 1.4.1-3-g733a5 From 92d66a131711bc7817e599c81d081847f689654c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 22:35:53 +0200 Subject: parser: document `parse_pat`. --- src/libsyntax/parse/parser/pat.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index e4a9dc00977..021e52798af 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -16,6 +16,10 @@ type Expected = Option<&'static str>; impl<'a> Parser<'a> { /// Parses a pattern. + /// + /// Corresponds to `pat` in RFC 2535 and does not admit or-patterns + /// at the top level. Used when parsing the parameters of lambda expressions, + /// functions, function pointers, and `pat` macro fragments. pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P> { self.parse_pat_with_range_pat(true, expected) } -- cgit 1.4.1-3-g733a5 From 95792b4d5a12276068e32f54c5d1561b8528a952 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 22:54:07 +0200 Subject: parser: `let` stmts & `for` exprs: allow or-patterns. --- src/libsyntax/parse/parser/expr.rs | 2 +- src/libsyntax/parse/parser/pat.rs | 6 ------ src/libsyntax/parse/parser/stmt.rs | 2 +- src/test/ui/parser/bad-match.rs | 2 +- src/test/ui/parser/bad-match.stderr | 4 ++-- src/test/ui/parser/bad-name.stderr | 4 ++-- src/test/ui/parser/issue-22647.rs | 2 +- src/test/ui/parser/issue-22647.stderr | 4 ++-- src/test/ui/parser/issue-22712.rs | 2 +- src/test/ui/parser/issue-22712.stderr | 4 ++-- src/test/ui/parser/issue-24197.rs | 2 +- src/test/ui/parser/issue-24197.stderr | 4 ++-- src/test/ui/parser/mut-patterns.rs | 3 ++- src/test/ui/parser/mut-patterns.stderr | 4 ++-- src/test/ui/parser/pat-lt-bracket-5.rs | 2 +- src/test/ui/parser/pat-lt-bracket-5.stderr | 4 ++-- src/test/ui/parser/pat-ranges-1.rs | 2 +- src/test/ui/parser/pat-ranges-1.stderr | 4 ++-- src/test/ui/parser/pat-ranges-2.rs | 2 +- src/test/ui/parser/pat-ranges-2.stderr | 4 ++-- src/test/ui/parser/pat-ranges-3.rs | 2 +- src/test/ui/parser/pat-ranges-3.stderr | 4 ++-- src/test/ui/parser/pat-ranges-4.rs | 2 +- src/test/ui/parser/pat-ranges-4.stderr | 4 ++-- 24 files changed, 35 insertions(+), 40 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index b9dd8518171..25a858b4735 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1284,7 +1284,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_level_pat()?; + let pat = self.parse_top_pat(true)?; if !self.eat_keyword(kw::In) { let in_span = self.prev_span.between(self.token.span); self.struct_span_err(in_span, "missing `in` in `for` loop") diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 021e52798af..e77d9120bce 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -45,12 +45,6 @@ impl<'a> Parser<'a> { self.parse_pat_with_or(None, gate_or, true) } - pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { - let pat = self.parse_pat(None)?; - self.maybe_recover_unexpected_comma(pat.span, true)?; - Ok(pat) - } - /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). /// Corresponds to `pat` in RFC 2535. fn parse_pat_with_or( diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index c911caba4cd..3c8cb4ea5a5 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -207,7 +207,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; - let pat = self.parse_top_level_pat()?; + let pat = self.parse_top_pat(true)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` diff --git a/src/test/ui/parser/bad-match.rs b/src/test/ui/parser/bad-match.rs index 79bc7eec311..04100d1701d 100644 --- a/src/test/ui/parser/bad-match.rs +++ b/src/test/ui/parser/bad-match.rs @@ -1,4 +1,4 @@ fn main() { - let isize x = 5; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `x` + let isize x = 5; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `x` match x; } diff --git a/src/test/ui/parser/bad-match.stderr b/src/test/ui/parser/bad-match.stderr index 2f29b978e9c..d5baaf5e93b 100644 --- a/src/test/ui/parser/bad-match.stderr +++ b/src/test/ui/parser/bad-match.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `x` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `x` --> $DIR/bad-match.rs:2:13 | LL | let isize x = 5; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/bad-name.stderr b/src/test/ui/parser/bad-name.stderr index 15e61cf06ca..dce4dabedf5 100644 --- a/src/test/ui/parser/bad-name.stderr +++ b/src/test/ui/parser/bad-name.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `.` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` --> $DIR/bad-name.rs:4:8 | LL | let x.y::.z foo; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-22647.rs b/src/test/ui/parser/issue-22647.rs index 25cd7ffce5a..a6861410682 100644 --- a/src/test/ui/parser/issue-22647.rs +++ b/src/test/ui/parser/issue-22647.rs @@ -1,5 +1,5 @@ fn main() { - let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` + let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<` where F: Fn() -> i32 { let x = f(); diff --git a/src/test/ui/parser/issue-22647.stderr b/src/test/ui/parser/issue-22647.stderr index 2dc56a5eca3..4b1ef4f3dfc 100644 --- a/src/test/ui/parser/issue-22647.stderr +++ b/src/test/ui/parser/issue-22647.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `<` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` --> $DIR/issue-22647.rs:2:15 | LL | let caller = |f: F| - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-22712.rs b/src/test/ui/parser/issue-22712.rs index b03d578e3d6..774de9c7e64 100644 --- a/src/test/ui/parser/issue-22712.rs +++ b/src/test/ui/parser/issue-22712.rs @@ -3,7 +3,7 @@ struct Foo { } fn bar() { - let Foo> //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` + let Foo> //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<` } fn main() {} diff --git a/src/test/ui/parser/issue-22712.stderr b/src/test/ui/parser/issue-22712.stderr index 167eaf962e0..d9e83144b36 100644 --- a/src/test/ui/parser/issue-22712.stderr +++ b/src/test/ui/parser/issue-22712.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `<` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` --> $DIR/issue-22712.rs:6:12 | LL | let Foo> - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-24197.rs b/src/test/ui/parser/issue-24197.rs index 005ff9fa2e0..aaf5137461f 100644 --- a/src/test/ui/parser/issue-24197.rs +++ b/src/test/ui/parser/issue-24197.rs @@ -1,3 +1,3 @@ fn main() { - let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` + let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` } diff --git a/src/test/ui/parser/issue-24197.stderr b/src/test/ui/parser/issue-24197.stderr index 2dfb31432bc..24818db622a 100644 --- a/src/test/ui/parser/issue-24197.stderr +++ b/src/test/ui/parser/issue-24197.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `[` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/issue-24197.rs:2:12 | LL | let buf[0] = 0; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index a5eb4825239..bffeb1e2e7c 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -2,5 +2,6 @@ pub fn main() { struct Foo { x: isize } - let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{` + let mut Foo { x: x } = Foo { x: 3 }; + //~^ ERROR: expected one of `:`, `;`, `=`, `@`, or `|`, found `{` } diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index 286956440ec..b39209afd42 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `{` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `{` --> $DIR/mut-patterns.rs:5:17 | LL | let mut Foo { x: x } = Foo { x: 3 }; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-5.rs b/src/test/ui/parser/pat-lt-bracket-5.rs index c4b9dd469f5..aaece1f6bd9 100644 --- a/src/test/ui/parser/pat-lt-bracket-5.rs +++ b/src/test/ui/parser/pat-lt-bracket-5.rs @@ -1,3 +1,3 @@ fn main() { - let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` + let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` } diff --git a/src/test/ui/parser/pat-lt-bracket-5.stderr b/src/test/ui/parser/pat-lt-bracket-5.stderr index ce4cc05db19..167314dde06 100644 --- a/src/test/ui/parser/pat-lt-bracket-5.stderr +++ b/src/test/ui/parser/pat-lt-bracket-5.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `[` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/pat-lt-bracket-5.rs:2:10 | LL | let v[0] = v[1]; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-1.rs b/src/test/ui/parser/pat-ranges-1.rs index ce953b2eb22..1dafb5a07bb 100644 --- a/src/test/ui/parser/pat-ranges-1.rs +++ b/src/test/ui/parser/pat-ranges-1.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `..=` + let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, `=`, or `|`, found `..=` } diff --git a/src/test/ui/parser/pat-ranges-1.stderr b/src/test/ui/parser/pat-ranges-1.stderr index 6e0deccab8c..4e2c5d28381 100644 --- a/src/test/ui/parser/pat-ranges-1.stderr +++ b/src/test/ui/parser/pat-ranges-1.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, or `=`, found `..=` +error: expected one of `:`, `;`, `=`, or `|`, found `..=` --> $DIR/pat-ranges-1.rs:4:21 | LL | let macropus!() ..= 11 = 12; - | ^^^ expected one of `:`, `;`, or `=` here + | ^^^ expected one of `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-2.rs b/src/test/ui/parser/pat-ranges-2.rs index 9f736ed328c..1593222acca 100644 --- a/src/test/ui/parser/pat-ranges-2.rs +++ b/src/test/ui/parser/pat-ranges-2.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` + let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, `=`, or `|`, found `!` } diff --git a/src/test/ui/parser/pat-ranges-2.stderr b/src/test/ui/parser/pat-ranges-2.stderr index d180bb42911..64df56f5a61 100644 --- a/src/test/ui/parser/pat-ranges-2.stderr +++ b/src/test/ui/parser/pat-ranges-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `::`, `:`, `;`, or `=`, found `!` +error: expected one of `::`, `:`, `;`, `=`, or `|`, found `!` --> $DIR/pat-ranges-2.rs:4:26 | LL | let 10 ..= makropulos!() = 12; - | ^ expected one of `::`, `:`, `;`, or `=` here + | ^ expected one of `::`, `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-3.rs b/src/test/ui/parser/pat-ranges-3.rs index 65da55e3bda..8976dcf0d90 100644 --- a/src/test/ui/parser/pat-ranges-3.rs +++ b/src/test/ui/parser/pat-ranges-3.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` + let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+` } diff --git a/src/test/ui/parser/pat-ranges-3.stderr b/src/test/ui/parser/pat-ranges-3.stderr index aaa85e3c2dd..c32c18d98dc 100644 --- a/src/test/ui/parser/pat-ranges-3.stderr +++ b/src/test/ui/parser/pat-ranges-3.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, or `=`, found `+` +error: expected one of `:`, `;`, `=`, or `|`, found `+` --> $DIR/pat-ranges-3.rs:4:19 | LL | let 10 ..= 10 + 3 = 12; - | ^ expected one of `:`, `;`, or `=` here + | ^ expected one of `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-4.rs b/src/test/ui/parser/pat-ranges-4.rs index 7f4a5f3239e..61188976b02 100644 --- a/src/test/ui/parser/pat-ranges-4.rs +++ b/src/test/ui/parser/pat-ranges-4.rs @@ -2,5 +2,5 @@ fn main() { let 10 - 3 ..= 10 = 8; - //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` + //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` } diff --git a/src/test/ui/parser/pat-ranges-4.stderr b/src/test/ui/parser/pat-ranges-4.stderr index 0a1d7a1f6b8..53e38bc670b 100644 --- a/src/test/ui/parser/pat-ranges-4.stderr +++ b/src/test/ui/parser/pat-ranges-4.stderr @@ -1,8 +1,8 @@ -error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` +error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` --> $DIR/pat-ranges-4.rs:4:12 | LL | let 10 - 3 ..= 10 = 8; - | ^ expected one of `...`, `..=`, `..`, `:`, `;`, or `=` here + | ^ expected one of 7 possible tokens here error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 5f6bec8ecf5a9018bb368becc0aaea703334795a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 18 Aug 2019 22:57:34 +0200 Subject: parser: drive-by: simplify `parse_arg_general`. --- src/libsyntax/parse/parser.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 89725d8b339..002e9bccec7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -971,15 +971,12 @@ impl<'a> Parser<'a> { /// Skips unexpected attributes and doc comments in this position and emits an appropriate /// error. /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general( + fn parse_arg_general( &mut self, is_trait_item: bool, allow_c_variadic: bool, - is_name_required: F, - ) -> PResult<'a, Arg> - where - F: Fn(&token::Token) -> bool - { + is_name_required: impl Fn(&token::Token) -> bool, + ) -> PResult<'a, Arg> { let lo = self.token.span; let attrs = self.parse_arg_attributes()?; if let Some(mut arg) = self.parse_self_arg()? { -- cgit 1.4.1-3-g733a5 From b205055c7bc92c0f873755996e6fac3e694c7e72 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 19 Aug 2019 02:40:24 +0200 Subject: parser: better recovery for || in inner pats. --- src/libsyntax/parse/parser/pat.rs | 27 ++++++-- .../ui/or-patterns/or-patterns-syntactic-fail.rs | 39 +++++------ .../or-patterns/or-patterns-syntactic-fail.stderr | 77 ++++++++++++++++------ 3 files changed, 96 insertions(+), 47 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index e77d9120bce..b9871be229c 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -155,6 +155,25 @@ impl<'a> Parser<'a> { Ok(()) } + /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. + /// See `parse_pat_with_or` for details on parsing or-patterns. + fn parse_pat_with_or_inner(&mut self, expected: Expected) -> PResult<'a, P> { + // Recover if `|` or `||` is here. + // The user is thinking that a leading `|` is allowed in this position. + if let token::BinOp(token::Or) | token::OrOr = self.token.kind { + let span = self.token.span; + let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); + + self.struct_span_err(span, "a leading `|` is only allowed in a top-level pattern") + .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable) + .emit(); + + self.bump(); + } + + self.parse_pat_with_or(expected, true, false) + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -173,7 +192,7 @@ impl<'a> Parser<'a> { // Parse `[pat, pat,...]` as a slice pattern. let (pats, _) = self.parse_delim_comma_seq( token::Bracket, - |p| p.parse_pat_with_or(None, true, false), + |p| p.parse_pat_with_or_inner(None), )?; PatKind::Slice(pats) } @@ -303,7 +322,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or(None, true, false) + p.parse_pat_with_or_inner(None) })?; // Here, `(pat,)` is a tuple pattern. @@ -547,7 +566,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true, false))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner(None))?; Ok(PatKind::TupleStruct(path, fields)) } @@ -691,7 +710,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or(None, true, false)?; + let pat = self.parse_pat_with_or_inner(None)?; hi = pat.span; (pat, fieldname, false) } else { diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs index 43c9214bd98..7959812f5b3 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -30,27 +30,20 @@ fn no_top_level_or_patterns() { // We also do not allow a leading `|` when not in a top level position: -#[cfg(FALSE)] -fn no_leading_parens() { - let ( | A | B); //~ ERROR expected pattern, found `|` -} - -#[cfg(FALSE)] -fn no_leading_tuple() { - let ( | A | B,); //~ ERROR expected pattern, found `|` -} - -#[cfg(FALSE)] -fn no_leading_slice() { - let [ | A | B ]; //~ ERROR expected pattern, found `|` -} - -#[cfg(FALSE)] -fn no_leading_tuple_struct() { - let TS( | A | B ); //~ ERROR expected pattern, found `|` -} - -#[cfg(FALSE)] -fn no_leading_struct() { - let NS { f: | A | B }; //~ ERROR expected pattern, found `|` +fn no_leading_inner() { + struct TS(E); + struct NS { f: E } + + let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern + + let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern + + let recovery_witness: String = 0; //~ ERROR mismatched types } diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 809ff272f62..dd4c309ce85 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -4,35 +4,59 @@ error: expected one of `:` or `@`, found `|` LL | fn fun(A | B: E) {} | ^ expected one of `:` or `@` here -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:35:11 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:37:11 | -LL | let ( | A | B); - | ^ expected pattern +LL | let ( | A | B) = E::A; + | ^ help: remove the `|` -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:40:11 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:38:11 | -LL | let ( | A | B,); - | ^ expected pattern +LL | let ( | A | B,) = (E::B,); + | ^ help: remove the `|` -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:45:11 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:39:11 | -LL | let [ | A | B ]; - | ^ expected pattern +LL | let [ | A | B ] = [E::A]; + | ^ help: remove the `|` -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:50:13 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:40:13 | LL | let TS( | A | B ); - | ^ expected pattern + | ^ help: remove the `|` -error: expected pattern, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:55:17 +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:41:17 | LL | let NS { f: | A | B }; - | ^ expected pattern + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:43:11 + | +LL | let ( || A | B) = E::A; + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:44:11 + | +LL | let [ || A | B ] = [E::A]; + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:45:13 + | +LL | let TS( || A | B ); + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:46:17 + | +LL | let NS { f: || A | B }; + | ^^ help: remove the `||` error: no rules expected the token `|` --> $DIR/or-patterns-syntactic-fail.rs:14:15 @@ -70,6 +94,19 @@ LL | let _ = |A | B: E| (); | = note: an implementation of `std::ops::BitOr` might be missing for `E` -error: aborting due to 9 previous errors +error[E0308]: mismatched types + --> $DIR/or-patterns-syntactic-fail.rs:48:36 + | +LL | let recovery_witness: String = 0; + | ^ + | | + | expected struct `std::string::String`, found integer + | help: try using a conversion method: `0.to_string()` + | + = note: expected type `std::string::String` + found type `{integer}` + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0369`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From b2966e651de3bf83ab9c712a1afaeba84162cab1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 21:43:28 +0200 Subject: parser: bool -> GateOr. --- src/libsyntax/parse/parser/expr.rs | 7 ++++--- src/libsyntax/parse/parser/pat.rs | 16 ++++++++++------ src/libsyntax/parse/parser/stmt.rs | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 25a858b4735..83e5a84a8c6 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1,6 +1,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle}; use super::{BlockMode, SemiColonMode}; use super::{SeqSep, TokenExpectType}; +use super::pat::GateOr; use crate::maybe_recover_from_interpolated_ty_qpath; use crate::ptr::P; @@ -1246,7 +1247,7 @@ impl<'a> Parser<'a> { fn parse_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. - let pat = self.parse_top_pat_unpack(false)?; + let pat = self.parse_top_pat_unpack(GateOr::No)?; self.expect(&token::Eq)?; let expr = self.with_res( Restrictions::NO_STRUCT_LITERAL, @@ -1284,7 +1285,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_pat(true)?; + let pat = self.parse_top_pat(GateOr::Yes)?; if !self.eat_keyword(kw::In) { let in_span = self.prev_span.between(self.token.span); self.struct_span_err(in_span, "missing `in` in `for` loop") @@ -1389,7 +1390,7 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. - let pat = self.parse_top_pat_unpack(false)?; + let pat = self.parse_top_pat_unpack(GateOr::No)?; let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index b9871be229c..3d89ec56ffa 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -14,6 +14,10 @@ use errors::{Applicability, DiagnosticBuilder}; type Expected = Option<&'static str>; +/// Whether or not an or-pattern should be gated when occurring in the current context. +#[derive(PartialEq)] +pub enum GateOr { Yes, No } + impl<'a> Parser<'a> { /// Parses a pattern. /// @@ -26,7 +30,7 @@ impl<'a> Parser<'a> { // FIXME(or_patterns, Centril | dlrobertson): // remove this and use `parse_top_pat` everywhere it is used instead. - pub(super) fn parse_top_pat_unpack(&mut self, gate_or: bool) -> PResult<'a, Vec>> { + pub(super) fn parse_top_pat_unpack(&mut self, gate_or: GateOr) -> PResult<'a, Vec>> { self.parse_top_pat(gate_or) .map(|pat| pat.and_then(|pat| match pat.node { PatKind::Or(pats) => pats, @@ -36,9 +40,9 @@ impl<'a> Parser<'a> { /// Entry point to the main pattern parser. /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. - pub(super) fn parse_top_pat(&mut self, gate_or: bool) -> PResult<'a, P> { + pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - if self.eat_or_separator() && gate_or { + if self.eat_or_separator() && gate_or == GateOr::Yes { self.sess.gated_spans.or_patterns.borrow_mut().push(self.prev_span); } @@ -50,7 +54,7 @@ impl<'a> Parser<'a> { fn parse_pat_with_or( &mut self, expected: Expected, - gate_or: bool, + gate_or: GateOr, top_level: bool ) -> PResult<'a, P> { // Parse the first pattern. @@ -73,7 +77,7 @@ impl<'a> Parser<'a> { let or_pattern_span = lo.to(self.prev_span); // Feature gate the or-pattern if instructed: - if gate_or { + if gate_or == GateOr::Yes { self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); } @@ -171,7 +175,7 @@ impl<'a> Parser<'a> { self.bump(); } - self.parse_pat_with_or(expected, true, false) + self.parse_pat_with_or(expected, GateOr::Yes, false) } /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index 3c8cb4ea5a5..651ebf6342e 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -1,6 +1,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, SemiColonMode, BlockMode}; use super::expr::LhsExpr; use super::path::PathStyle; +use super::pat::GateOr; use crate::ptr::P; use crate::{maybe_whole, ThinVec}; @@ -207,7 +208,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; - let pat = self.parse_top_pat(true)?; + let pat = self.parse_top_pat(GateOr::Yes)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` -- cgit 1.4.1-3-g733a5 From a9ef8592e47808539ffd9237c22ce5518aa7b188 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 22:12:19 +0200 Subject: parser: bool -> TopLevel. --- src/libsyntax/parse/parser/pat.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 3d89ec56ffa..c168d033781 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -18,6 +18,10 @@ type Expected = Option<&'static str>; #[derive(PartialEq)] pub enum GateOr { Yes, No } +/// Whether or not this is the top level pattern context. +#[derive(PartialEq, Copy, Clone)] +enum TopLevel { Yes, No } + impl<'a> Parser<'a> { /// Parses a pattern. /// @@ -46,7 +50,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.or_patterns.borrow_mut().push(self.prev_span); } - self.parse_pat_with_or(None, gate_or, true) + self.parse_pat_with_or(None, gate_or, TopLevel::Yes) } /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). @@ -55,7 +59,7 @@ impl<'a> Parser<'a> { &mut self, expected: Expected, gate_or: GateOr, - top_level: bool + top_level: TopLevel, ) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; @@ -112,8 +116,8 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: bool) -> PResult<'a, ()> { - if !top_level || self.token != token::Comma { + fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: TopLevel) -> PResult<'a, ()> { + if top_level == TopLevel::No || self.token != token::Comma { return Ok(()); } @@ -175,7 +179,7 @@ impl<'a> Parser<'a> { self.bump(); } - self.parse_pat_with_or(expected, GateOr::Yes, false) + self.parse_pat_with_or(expected, GateOr::Yes, TopLevel::No) } /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are -- cgit 1.4.1-3-g733a5 From 3a405421e7c1437416e225ea8d2f0fdfb501df7b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 22:46:17 +0200 Subject: parse_top_pat: silence leading vert gating sometimes. --- src/libsyntax/parse/parser/pat.rs | 18 +++++++-- .../feature-gate-or_patterns-leading-for.rs | 8 ++++ .../feature-gate-or_patterns-leading-for.stderr | 12 ++++++ .../feature-gate-or_patterns-leading-let.rs | 8 ++++ .../feature-gate-or_patterns-leading-let.stderr | 12 ++++++ .../feature-gate-or_patterns-leading.stderr | 12 ++++++ .../ui/or-patterns/feature-gate-or_patterns.rs | 2 - .../ui/or-patterns/feature-gate-or_patterns.stderr | 44 +++++++--------------- 8 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr create mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index c168d033781..724edbcfaed 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -46,11 +46,23 @@ impl<'a> Parser<'a> { /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - if self.eat_or_separator() && gate_or == GateOr::Yes { - self.sess.gated_spans.or_patterns.borrow_mut().push(self.prev_span); + let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; + + // Parse the possibly-or-pattern. + let pat = self.parse_pat_with_or(None, gate_or, TopLevel::Yes)?; + + // If we parsed a leading `|` which should be gated, + // and no other gated or-pattern has been parsed thus far, + // then we should really gate the leading `|`. + // This complicated procedure is done purely for diagnostics UX. + if gated_leading_vert { + let mut or_pattern_spans = self.sess.gated_spans.or_patterns.borrow_mut(); + if or_pattern_spans.is_empty() { + or_pattern_spans.push(self.prev_span); + } } - self.parse_pat_with_or(None, gate_or, TopLevel::Yes) + Ok(pat) } /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs new file mode 100644 index 00000000000..de8e1bba557 --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs @@ -0,0 +1,8 @@ +// Test feature gating for a sole leading `|` in `let`. + +fn main() {} + +#[cfg(FALSE)] +fn gated_leading_vert_in_let() { + for | A in 0 {} //~ ERROR or-patterns syntax is experimental +} diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr new file mode 100644 index 00000000000..83804d564f3 --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr @@ -0,0 +1,12 @@ +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns-leading-for.rs:7:11 + | +LL | for | A in 0 {} + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs new file mode 100644 index 00000000000..a4ea4e25d86 --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs @@ -0,0 +1,8 @@ +// Test feature gating for a sole leading `|` in `let`. + +fn main() {} + +#[cfg(FALSE)] +fn gated_leading_vert_in_let() { + let | A; //~ ERROR or-patterns syntax is experimental +} diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr new file mode 100644 index 00000000000..f7954ad7a8c --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr @@ -0,0 +1,12 @@ +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns-leading-let.rs:7:11 + | +LL | let | A; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr new file mode 100644 index 00000000000..8b18082fca7 --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr @@ -0,0 +1,12 @@ +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns-leading.rs:7:11 + | +LL | let | A; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.rs b/src/test/ui/or-patterns/feature-gate-or_patterns.rs index 560db20e668..e638838147a 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns.rs +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.rs @@ -26,10 +26,8 @@ fn or_patterns() { // Gated: let | A | B; //~ ERROR or-patterns syntax is experimental - //~^ ERROR or-patterns syntax is experimental let A | B; //~ ERROR or-patterns syntax is experimental for | A | B in 0 {} //~ ERROR or-patterns syntax is experimental - //~^ ERROR or-patterns syntax is experimental for A | B in 0 {} //~ ERROR or-patterns syntax is experimental fn fun((A | B): _) {} //~ ERROR or-patterns syntax is experimental let _ = |(A | B): u8| (); //~ ERROR or-patterns syntax is experimental diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr index e2abfbfd525..aae6644dac2 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr @@ -7,15 +7,6 @@ LL | Some(0 | 1 | 2) => {} = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable -error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:28:9 - | -LL | let | A | B; - | ^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54883 - = help: add `#![feature(or_patterns)]` to the crate attributes to enable - error[E0658]: or-patterns syntax is experimental --> $DIR/feature-gate-or_patterns.rs:28:11 | @@ -26,7 +17,7 @@ LL | let | A | B; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:30:9 + --> $DIR/feature-gate-or_patterns.rs:29:9 | LL | let A | B; | ^^^^^ @@ -35,16 +26,7 @@ LL | let A | B; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:31:9 - | -LL | for | A | B in 0 {} - | ^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54883 - = help: add `#![feature(or_patterns)]` to the crate attributes to enable - -error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:31:11 + --> $DIR/feature-gate-or_patterns.rs:30:11 | LL | for | A | B in 0 {} | ^^^^^ @@ -53,7 +35,7 @@ LL | for | A | B in 0 {} = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:33:9 + --> $DIR/feature-gate-or_patterns.rs:31:9 | LL | for A | B in 0 {} | ^^^^^ @@ -62,7 +44,7 @@ LL | for A | B in 0 {} = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:34:13 + --> $DIR/feature-gate-or_patterns.rs:32:13 | LL | fn fun((A | B): _) {} | ^^^^^ @@ -71,7 +53,7 @@ LL | fn fun((A | B): _) {} = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:35:15 + --> $DIR/feature-gate-or_patterns.rs:33:15 | LL | let _ = |(A | B): u8| (); | ^^^^^ @@ -80,7 +62,7 @@ LL | let _ = |(A | B): u8| (); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:36:10 + --> $DIR/feature-gate-or_patterns.rs:34:10 | LL | let (A | B); | ^^^^^ @@ -89,7 +71,7 @@ LL | let (A | B); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:37:10 + --> $DIR/feature-gate-or_patterns.rs:35:10 | LL | let (A | B,); | ^^^^^ @@ -98,7 +80,7 @@ LL | let (A | B,); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:38:11 + --> $DIR/feature-gate-or_patterns.rs:36:11 | LL | let A(B | C); | ^^^^^ @@ -107,7 +89,7 @@ LL | let A(B | C); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:39:14 + --> $DIR/feature-gate-or_patterns.rs:37:14 | LL | let E::V(B | C); | ^^^^^ @@ -116,7 +98,7 @@ LL | let E::V(B | C); = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:40:17 + --> $DIR/feature-gate-or_patterns.rs:38:17 | LL | let S { f1: B | C, f2 }; | ^^^^^ @@ -125,7 +107,7 @@ LL | let S { f1: B | C, f2 }; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:41:20 + --> $DIR/feature-gate-or_patterns.rs:39:20 | LL | let E::V { f1: B | C, f2 }; | ^^^^^ @@ -134,7 +116,7 @@ LL | let E::V { f1: B | C, f2 }; = help: add `#![feature(or_patterns)]` to the crate attributes to enable error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:42:10 + --> $DIR/feature-gate-or_patterns.rs:40:10 | LL | let [A | B]; | ^^^^^ @@ -187,6 +169,6 @@ LL | accept_pat!([p | q]); = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable -error: aborting due to 21 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From e3747722fbb8a44f9053922e4c39338a3a1f9597 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 23:10:46 +0200 Subject: parser: extract recover_inner_leading_vert. --- src/libsyntax/parse/parser/pat.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 724edbcfaed..dc6632cf10d 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -178,8 +178,13 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self, expected: Expected) -> PResult<'a, P> { - // Recover if `|` or `||` is here. - // The user is thinking that a leading `|` is allowed in this position. + self.recover_inner_leading_vert(); + self.parse_pat_with_or(expected, GateOr::Yes, TopLevel::No) + } + + /// Recover if `|` or `||` is here. + /// The user is thinking that a leading `|` is allowed in this position. + fn recover_inner_leading_vert(&mut self) { if let token::BinOp(token::Or) | token::OrOr = self.token.kind { let span = self.token.span; let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); @@ -190,8 +195,6 @@ impl<'a> Parser<'a> { self.bump(); } - - self.parse_pat_with_or(expected, GateOr::Yes, TopLevel::No) } /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are -- cgit 1.4.1-3-g733a5 From 0ab84303326fff65d5d0a168fd47448e05135c9f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 24 Aug 2019 23:44:28 +0200 Subject: parser: reword || recovery. --- src/libsyntax/parse/parser/pat.rs | 2 +- src/test/ui/or-patterns/multiple-pattern-typo.stderr | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index dc6632cf10d..0b3de57fd6f 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -119,7 +119,7 @@ impl<'a> Parser<'a> { self.struct_span_err(self.token.span, "unexpected token `||` after pattern") .span_suggestion( self.token.span, - "use a single `|` to specify multiple patterns", + "use a single `|` to separate multiple alternative patterns", "|".to_owned(), Applicability::MachineApplicable ) diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index 765c7879b12..c61b5cb2082 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -2,43 +2,43 @@ error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:8:15 | LL | 1 | 2 || 3 => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:13:16 | LL | (1 | 2 || 3) => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:18:16 | LL | (1 | 2 || 3,) => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:25:18 | LL | TS(1 | 2 || 3) => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:32:23 | LL | NS { f: 1 | 2 || 3 } => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:37:16 | LL | [1 | 2 || 3] => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:42:9 | LL | || 1 | 2 | 3 => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` warning: the feature `or_patterns` is incomplete and may cause the compiler to crash --> $DIR/multiple-pattern-typo.rs:1:12 -- cgit 1.4.1-3-g733a5 From 1202cb0e2b168b0a913b33e3cb3c1d9339683e28 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 01:00:19 +0200 Subject: parser: simplify parse_pat_with_or_{inner} --- src/libsyntax/parse/parser/pat.rs | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 0b3de57fd6f..7c09dc4e566 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -49,7 +49,7 @@ impl<'a> Parser<'a> { let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, TopLevel::Yes)?; + let pat = self.parse_pat_with_or(gate_or, TopLevel::Yes)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, @@ -67,14 +67,9 @@ impl<'a> Parser<'a> { /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). /// Corresponds to `pat` in RFC 2535. - fn parse_pat_with_or( - &mut self, - expected: Expected, - gate_or: GateOr, - top_level: TopLevel, - ) -> PResult<'a, P> { + fn parse_pat_with_or(&mut self, gate_or: GateOr, top_level: TopLevel) -> PResult<'a, P> { // Parse the first pattern. - let first_pat = self.parse_pat(expected)?; + let first_pat = self.parse_pat(None)?; self.maybe_recover_unexpected_comma(first_pat.span, top_level)?; // If the next token is not a `|`, @@ -86,7 +81,7 @@ impl<'a> Parser<'a> { let lo = first_pat.span; let mut pats = vec![first_pat]; while self.eat_or_separator() { - let pat = self.parse_pat(expected)?; + let pat = self.parse_pat(None)?; self.maybe_recover_unexpected_comma(pat.span, top_level)?; pats.push(pat); } @@ -177,9 +172,9 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. - fn parse_pat_with_or_inner(&mut self, expected: Expected) -> PResult<'a, P> { + fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { self.recover_inner_leading_vert(); - self.parse_pat_with_or(expected, GateOr::Yes, TopLevel::No) + self.parse_pat_with_or(GateOr::Yes, TopLevel::No) } /// Recover if `|` or `||` is here. @@ -215,7 +210,7 @@ impl<'a> Parser<'a> { // Parse `[pat, pat,...]` as a slice pattern. let (pats, _) = self.parse_delim_comma_seq( token::Bracket, - |p| p.parse_pat_with_or_inner(None), + |p| p.parse_pat_with_or_inner(), )?; PatKind::Slice(pats) } @@ -344,9 +339,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { - let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or_inner(None) - })?; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. @@ -589,7 +582,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner(None))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; Ok(PatKind::TupleStruct(path, fields)) } @@ -733,7 +726,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or_inner(None)?; + let pat = self.parse_pat_with_or_inner()?; hi = pat.span; (pat, fieldname, false) } else { -- cgit 1.4.1-3-g733a5 From 083963e58c752f1a51b67d65dc6a207bf69f1d64 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 01:50:21 +0200 Subject: parser: 'while parsing this or-pattern...' --- src/libsyntax/parse/parser/pat.rs | 5 ++++- src/test/ui/or-patterns/while-parsing-this-or-pattern.rs | 9 +++++++++ src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr | 10 ++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/or-patterns/while-parsing-this-or-pattern.rs create mode 100644 src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 7c09dc4e566..a0278fa4077 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -81,7 +81,10 @@ impl<'a> Parser<'a> { let lo = first_pat.span; let mut pats = vec![first_pat]; while self.eat_or_separator() { - let pat = self.parse_pat(None)?; + let pat = self.parse_pat(None).map_err(|mut err| { + err.span_label(lo, "while parsing this or-pattern staring here"); + err + })?; self.maybe_recover_unexpected_comma(pat.span, top_level)?; pats.push(pat); } diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs new file mode 100644 index 00000000000..4a9fae1406a --- /dev/null +++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs @@ -0,0 +1,9 @@ +// Test the parser for the "while parsing this or-pattern..." label here. + +fn main() { + match Some(42) { + Some(42) | .=. => {} //~ ERROR expected pattern, found `.` + //~^ while parsing this or-pattern staring here + //~| NOTE expected pattern + } +} diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr new file mode 100644 index 00000000000..21fece6c64f --- /dev/null +++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr @@ -0,0 +1,10 @@ +error: expected pattern, found `.` + --> $DIR/while-parsing-this-or-pattern.rs:5:20 + | +LL | Some(42) | .=. => {} + | -------- ^ expected pattern + | | + | while parsing this or-pattern staring here + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 1caaa40768fecb91b322b1e1befc91c54b56817c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 04:39:28 +0200 Subject: parser: gracefully handle `fn foo(A | B: type)`. --- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/parse/parser/expr.rs | 4 +- src/libsyntax/parse/parser/pat.rs | 46 ++++++++++++++++++---- src/test/ui/anon-params-denied-2018.rs | 2 +- src/test/ui/anon-params-denied-2018.stderr | 16 ++++---- .../feature-gate-or_patterns-leading.stderr | 12 ------ .../ui/or-patterns/or-patterns-syntactic-fail.rs | 6 ++- .../or-patterns/or-patterns-syntactic-fail.stderr | 42 +++++++++++++------- src/test/ui/parser/inverted-parameters.rs | 12 +++--- src/test/ui/parser/inverted-parameters.stderr | 24 +++++------ src/test/ui/parser/issue-33413.rs | 2 +- src/test/ui/parser/issue-33413.stderr | 4 +- src/test/ui/parser/issue-63135.rs | 2 +- src/test/ui/parser/issue-63135.stderr | 12 ++---- src/test/ui/parser/omitted-arg-in-item-fn.rs | 2 +- src/test/ui/parser/omitted-arg-in-item-fn.stderr | 4 +- src/test/ui/parser/pat-lt-bracket-2.rs | 2 +- src/test/ui/parser/pat-lt-bracket-2.stderr | 4 +- src/test/ui/parser/removed-syntax-mode.rs | 2 +- src/test/ui/parser/removed-syntax-mode.stderr | 4 +- .../ui/rfc-2565-param-attrs/param-attrs-2018.rs | 2 +- .../rfc-2565-param-attrs/param-attrs-2018.stderr | 4 +- src/test/ui/span/issue-34264.stderr | 12 +++--- 23 files changed, 125 insertions(+), 97 deletions(-) delete mode 100644 src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 002e9bccec7..25ad2d4404c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -988,7 +988,7 @@ impl<'a> Parser<'a> { let (pat, ty) = if is_name_required || self.is_named_argument() { debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required); - let pat = self.parse_pat(Some("argument name"))?; + let pat = self.parse_fn_param_pat()?; if let Err(mut err) = self.expect(&token::Colon) { if let Some(ident) = self.argument_without_type( &mut err, diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 83e5a84a8c6..f7c090b5135 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1,7 +1,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle}; use super::{BlockMode, SemiColonMode}; use super::{SeqSep, TokenExpectType}; -use super::pat::GateOr; +use super::pat::{GateOr, PARAM_EXPECTED}; use crate::maybe_recover_from_interpolated_ty_qpath; use crate::ptr::P; @@ -1176,7 +1176,7 @@ impl<'a> Parser<'a> { fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { let lo = self.token.span; let attrs = self.parse_arg_attributes()?; - let pat = self.parse_pat(Some("argument name"))?; + let pat = self.parse_pat(PARAM_EXPECTED)?; let t = if self.eat(&token::Colon) { self.parse_ty()? } else { diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index a0278fa4077..1541031ec25 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -14,6 +14,9 @@ use errors::{Applicability, DiagnosticBuilder}; type Expected = Option<&'static str>; +/// `Expected` for function and lambda parameter patterns. +pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); + /// Whether or not an or-pattern should be gated when occurring in the current context. #[derive(PartialEq)] pub enum GateOr { Yes, No } @@ -49,7 +52,7 @@ impl<'a> Parser<'a> { let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(gate_or, TopLevel::Yes)?; + let pat = self.parse_pat_with_or(None, gate_or, TopLevel::Yes)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, @@ -65,11 +68,38 @@ impl<'a> Parser<'a> { Ok(pat) } + /// Parse the pattern for a function or function pointer parameter. + /// Special recovery is provided for or-patterns and leading `|`. + pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { + self.recover_leading_vert("not allowed in a parameter pattern"); + let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, TopLevel::No)?; + + if let PatKind::Or(..) = &pat.node { + self.ban_illegal_fn_param_or_pat(&pat); + } + + Ok(pat) + } + + /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. + fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) { + let msg = "wrap the pattern in parenthesis"; + let fix = format!("({})", pprust::pat_to_string(pat)); + self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parenthesis") + .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable) + .emit(); + } + /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). /// Corresponds to `pat` in RFC 2535. - fn parse_pat_with_or(&mut self, gate_or: GateOr, top_level: TopLevel) -> PResult<'a, P> { + fn parse_pat_with_or( + &mut self, + expected: Expected, + gate_or: GateOr, + top_level: TopLevel, + ) -> PResult<'a, P> { // Parse the first pattern. - let first_pat = self.parse_pat(None)?; + let first_pat = self.parse_pat(expected)?; self.maybe_recover_unexpected_comma(first_pat.span, top_level)?; // If the next token is not a `|`, @@ -81,7 +111,7 @@ impl<'a> Parser<'a> { let lo = first_pat.span; let mut pats = vec![first_pat]; while self.eat_or_separator() { - let pat = self.parse_pat(None).map_err(|mut err| { + let pat = self.parse_pat(expected).map_err(|mut err| { err.span_label(lo, "while parsing this or-pattern staring here"); err })?; @@ -176,18 +206,18 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { - self.recover_inner_leading_vert(); - self.parse_pat_with_or(GateOr::Yes, TopLevel::No) + self.recover_leading_vert("only allowed in a top-level pattern"); + self.parse_pat_with_or(None, GateOr::Yes, TopLevel::No) } /// Recover if `|` or `||` is here. /// The user is thinking that a leading `|` is allowed in this position. - fn recover_inner_leading_vert(&mut self) { + fn recover_leading_vert(&mut self, ctx: &str) { if let token::BinOp(token::Or) | token::OrOr = self.token.kind { let span = self.token.span; let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); - self.struct_span_err(span, "a leading `|` is only allowed in a top-level pattern") + self.struct_span_err(span, &format!("a leading `|` is {}", ctx)) .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable) .emit(); diff --git a/src/test/ui/anon-params-denied-2018.rs b/src/test/ui/anon-params-denied-2018.rs index abff8275064..5721f5d2357 100644 --- a/src/test/ui/anon-params-denied-2018.rs +++ b/src/test/ui/anon-params-denied-2018.rs @@ -3,7 +3,7 @@ // edition:2018 trait T { - fn foo(i32); //~ expected one of `:` or `@`, found `)` + fn foo(i32); //~ expected one of `:`, `@`, or `|`, found `)` fn bar_with_default_impl(String, String) {} //~^ ERROR expected one of `:` diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params-denied-2018.stderr index 438bcf4274d..a58998e4891 100644 --- a/src/test/ui/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params-denied-2018.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:6:15 | LL | fn foo(i32); - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -14,11 +14,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn foo(_: i32); | ^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:8:36 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -30,11 +30,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar_with_default_impl(_: String, String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:8:44 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -46,11 +46,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar_with_default_impl(String, _: String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:13:22 | LL | fn baz(a:usize, b, c: usize) -> usize { - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr deleted file mode 100644 index 8b18082fca7..00000000000 --- a/src/test/ui/or-patterns/feature-gate-or_patterns-leading.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns-leading.rs:7:11 - | -LL | let | A; - | ^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54883 - = help: add `#![feature(or_patterns)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs index 7959812f5b3..b676ea851a3 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -25,7 +25,11 @@ fn no_top_level_or_patterns() { // -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`. // ...and for now neither do we allow or-patterns at the top level of functions. - fn fun(A | B: E) {} //~ ERROR expected one of `:` or `@`, found `|` + fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis + + fn fun2(| A | B: E) {} + //~^ ERROR a leading `|` is not allowed in a parameter pattern + //~| ERROR an or-pattern parameter must be wrapped in parenthesis } // We also do not allow a leading `|` when not in a top level position: diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index dd4c309ce85..2a3a6abfb7b 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -1,59 +1,71 @@ -error: expected one of `:` or `@`, found `|` - --> $DIR/or-patterns-syntactic-fail.rs:28:14 +error: an or-pattern parameter must be wrapped in parenthesis + --> $DIR/or-patterns-syntactic-fail.rs:28:13 | -LL | fn fun(A | B: E) {} - | ^ expected one of `:` or `@` here +LL | fn fun1(A | B: E) {} + | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + +error: a leading `|` is not allowed in a parameter pattern + --> $DIR/or-patterns-syntactic-fail.rs:30:13 + | +LL | fn fun2(| A | B: E) {} + | ^ help: remove the `|` + +error: an or-pattern parameter must be wrapped in parenthesis + --> $DIR/or-patterns-syntactic-fail.rs:30:15 + | +LL | fn fun2(| A | B: E) {} + | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:37:11 + --> $DIR/or-patterns-syntactic-fail.rs:41:11 | LL | let ( | A | B) = E::A; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:38:11 + --> $DIR/or-patterns-syntactic-fail.rs:42:11 | LL | let ( | A | B,) = (E::B,); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:39:11 + --> $DIR/or-patterns-syntactic-fail.rs:43:11 | LL | let [ | A | B ] = [E::A]; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:40:13 + --> $DIR/or-patterns-syntactic-fail.rs:44:13 | LL | let TS( | A | B ); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:41:17 + --> $DIR/or-patterns-syntactic-fail.rs:45:17 | LL | let NS { f: | A | B }; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:43:11 + --> $DIR/or-patterns-syntactic-fail.rs:47:11 | LL | let ( || A | B) = E::A; | ^^ help: remove the `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:44:11 + --> $DIR/or-patterns-syntactic-fail.rs:48:11 | LL | let [ || A | B ] = [E::A]; | ^^ help: remove the `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:45:13 + --> $DIR/or-patterns-syntactic-fail.rs:49:13 | LL | let TS( || A | B ); | ^^ help: remove the `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:46:17 + --> $DIR/or-patterns-syntactic-fail.rs:50:17 | LL | let NS { f: || A | B }; | ^^ help: remove the `||` @@ -95,7 +107,7 @@ LL | let _ = |A | B: E| (); = note: an implementation of `std::ops::BitOr` might be missing for `E` error[E0308]: mismatched types - --> $DIR/or-patterns-syntactic-fail.rs:48:36 + --> $DIR/or-patterns-syntactic-fail.rs:52:36 | LL | let recovery_witness: String = 0; | ^ @@ -106,7 +118,7 @@ LL | let recovery_witness: String = 0; = note: expected type `std::string::String` found type `{integer}` -error: aborting due to 14 previous errors +error: aborting due to 16 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/inverted-parameters.rs b/src/test/ui/parser/inverted-parameters.rs index f06b9510417..d6efc8be072 100644 --- a/src/test/ui/parser/inverted-parameters.rs +++ b/src/test/ui/parser/inverted-parameters.rs @@ -2,29 +2,29 @@ struct S; impl S { fn foo(&self, &str bar) {} - //~^ ERROR expected one of `:` or `@` + //~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : } fn baz(S quux, xyzzy: i32) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : fn one(i32 a b) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` fn pattern((i32, i32) (a, b)) {} -//~^ ERROR expected `:` +//~^ ERROR expected one of `:` fn fizz(i32) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP if this was a parameter name, give it a type //~| HELP if this is a type, explicitly ignore the parameter name fn missing_colon(quux S) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : diff --git a/src/test/ui/parser/inverted-parameters.stderr b/src/test/ui/parser/inverted-parameters.stderr index fb48bd1fe93..2bda4460031 100644 --- a/src/test/ui/parser/inverted-parameters.stderr +++ b/src/test/ui/parser/inverted-parameters.stderr @@ -1,38 +1,38 @@ -error: expected one of `:` or `@`, found `bar` +error: expected one of `:`, `@`, or `|`, found `bar` --> $DIR/inverted-parameters.rs:4:24 | LL | fn foo(&self, &str bar) {} | -----^^^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` -error: expected one of `:` or `@`, found `quux` +error: expected one of `:`, `@`, or `|`, found `quux` --> $DIR/inverted-parameters.rs:10:10 | LL | fn baz(S quux, xyzzy: i32) {} | --^^^^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` -error: expected one of `:` or `@`, found `a` +error: expected one of `:`, `@`, or `|`, found `a` --> $DIR/inverted-parameters.rs:15:12 | LL | fn one(i32 a b) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here -error: expected `:`, found `(` +error: expected one of `:` or `|`, found `(` --> $DIR/inverted-parameters.rs:18:23 | LL | fn pattern((i32, i32) (a, b)) {} - | ^ expected `:` + | ^ expected one of `:` or `|` here -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/inverted-parameters.rs:21:12 | LL | fn fizz(i32) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -44,13 +44,13 @@ help: if this is a type, explicitly ignore the parameter name LL | fn fizz(_: i32) {} | ^^^^^^ -error: expected one of `:` or `@`, found `S` +error: expected one of `:`, `@`, or `|`, found `S` --> $DIR/inverted-parameters.rs:26:23 | LL | fn missing_colon(quux S) {} | -----^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/issue-33413.rs b/src/test/ui/parser/issue-33413.rs index 2ec86958174..22f80a8aae8 100644 --- a/src/test/ui/parser/issue-33413.rs +++ b/src/test/ui/parser/issue-33413.rs @@ -2,7 +2,7 @@ struct S; impl S { fn f(*, a: u8) -> u8 {} - //~^ ERROR expected argument name, found `*` + //~^ ERROR expected parameter name, found `*` } fn main() {} diff --git a/src/test/ui/parser/issue-33413.stderr b/src/test/ui/parser/issue-33413.stderr index f6f096b1b9a..9e1178e8ac1 100644 --- a/src/test/ui/parser/issue-33413.stderr +++ b/src/test/ui/parser/issue-33413.stderr @@ -1,8 +1,8 @@ -error: expected argument name, found `*` +error: expected parameter name, found `*` --> $DIR/issue-33413.rs:4:10 | LL | fn f(*, a: u8) -> u8 {} - | ^ expected argument name + | ^ expected parameter name error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63135.rs b/src/test/ui/parser/issue-63135.rs index d5f5f1469f3..a5a8de85466 100644 --- a/src/test/ui/parser/issue-63135.rs +++ b/src/test/ui/parser/issue-63135.rs @@ -1,3 +1,3 @@ -// error-pattern: aborting due to 6 previous errors +// error-pattern: aborting due to 5 previous errors fn i(n{...,f # diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index c0286d90af7..a077ad454a9 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -28,17 +28,11 @@ error: expected `[`, found `}` LL | fn i(n{...,f # | ^ expected `[` -error: expected `:`, found `)` +error: expected one of `:` or `|`, found `)` --> $DIR/issue-63135.rs:3:15 | LL | fn i(n{...,f # - | ^ expected `:` + | ^ expected one of `:` or `|` here -error: expected one of `->`, `where`, or `{`, found `` - --> $DIR/issue-63135.rs:3:15 - | -LL | fn i(n{...,f # - | ^ expected one of `->`, `where`, or `{` here - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.rs b/src/test/ui/parser/omitted-arg-in-item-fn.rs index 5ee9daf4640..49cbc4d6bf4 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.rs +++ b/src/test/ui/parser/omitted-arg-in-item-fn.rs @@ -1,4 +1,4 @@ -fn foo(x) { //~ ERROR expected one of `:` or `@`, found `)` +fn foo(x) { //~ ERROR expected one of `:`, `@`, or `|`, found `)` } fn main() {} diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.stderr b/src/test/ui/parser/omitted-arg-in-item-fn.stderr index e501f235d6d..7feb15592c5 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.stderr +++ b/src/test/ui/parser/omitted-arg-in-item-fn.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/omitted-arg-in-item-fn.rs:1:9 | LL | fn foo(x) { - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/parser/pat-lt-bracket-2.rs b/src/test/ui/parser/pat-lt-bracket-2.rs index 6eb01c1c933..3a778ed14f6 100644 --- a/src/test/ui/parser/pat-lt-bracket-2.rs +++ b/src/test/ui/parser/pat-lt-bracket-2.rs @@ -1,4 +1,4 @@ fn a(B<) {} - //~^ error: expected one of `:` or `@`, found `<` + //~^ error: expected one of `:`, `@`, or `|`, found `<` fn main() {} diff --git a/src/test/ui/parser/pat-lt-bracket-2.stderr b/src/test/ui/parser/pat-lt-bracket-2.stderr index cce1a17e9e8..dbc8d0f5865 100644 --- a/src/test/ui/parser/pat-lt-bracket-2.stderr +++ b/src/test/ui/parser/pat-lt-bracket-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/pat-lt-bracket-2.rs:1:7 | LL | fn a(B<) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-mode.rs b/src/test/ui/parser/removed-syntax-mode.rs index 23851b5f70b..a438db3b0c1 100644 --- a/src/test/ui/parser/removed-syntax-mode.rs +++ b/src/test/ui/parser/removed-syntax-mode.rs @@ -1,4 +1,4 @@ fn f(+x: isize) {} -//~^ ERROR expected argument name, found `+` +//~^ ERROR expected parameter name, found `+` fn main() {} diff --git a/src/test/ui/parser/removed-syntax-mode.stderr b/src/test/ui/parser/removed-syntax-mode.stderr index 5e7139d6bfd..d0393b379f0 100644 --- a/src/test/ui/parser/removed-syntax-mode.stderr +++ b/src/test/ui/parser/removed-syntax-mode.stderr @@ -1,8 +1,8 @@ -error: expected argument name, found `+` +error: expected parameter name, found `+` --> $DIR/removed-syntax-mode.rs:1:6 | LL | fn f(+x: isize) {} - | ^ expected argument name + | ^ expected parameter name error: aborting due to previous error diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs index e900ccab4fd..d71711336b0 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs @@ -3,6 +3,6 @@ #![feature(param_attrs)] trait Trait2015 { fn foo(#[allow(C)] i32); } -//~^ ERROR expected one of `:` or `@`, found `)` +//~^ ERROR expected one of `:`, `@`, or `|`, found `)` fn main() {} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr index d0ed65f2880..26b414e4268 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/param-attrs-2018.rs:5:41 | LL | trait Trait2015 { fn foo(#[allow(C)] i32); } - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 5dd9895c6e4..cc0eccd37a2 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -1,14 +1,14 @@ -error: expected one of `:` or `@`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-34264.rs:1:14 | LL | fn foo(Option, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/issue-34264.rs:1:27 | LL | fn foo(Option, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -20,11 +20,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn foo(Option, _: String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/issue-34264.rs:3:9 | LL | fn bar(x, y: usize) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type -- cgit 1.4.1-3-g733a5 From acb11305e8d7298750797d45324c0ecb3cc6c256 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 25 Aug 2019 06:15:11 +0200 Subject: parser: TopLevel -> RecoverComma. --- src/libsyntax/parse/parser/pat.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 1541031ec25..f2e269e03ba 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -21,9 +21,9 @@ pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); #[derive(PartialEq)] pub enum GateOr { Yes, No } -/// Whether or not this is the top level pattern context. +/// Whether or not to recover a `,` when parsing or-patterns. #[derive(PartialEq, Copy, Clone)] -enum TopLevel { Yes, No } +enum RecoverComma { Yes, No } impl<'a> Parser<'a> { /// Parses a pattern. @@ -52,7 +52,7 @@ impl<'a> Parser<'a> { let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, TopLevel::Yes)?; + let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, @@ -72,7 +72,7 @@ impl<'a> Parser<'a> { /// Special recovery is provided for or-patterns and leading `|`. pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { self.recover_leading_vert("not allowed in a parameter pattern"); - let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, TopLevel::No)?; + let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; if let PatKind::Or(..) = &pat.node { self.ban_illegal_fn_param_or_pat(&pat); @@ -96,11 +96,11 @@ impl<'a> Parser<'a> { &mut self, expected: Expected, gate_or: GateOr, - top_level: TopLevel, + rc: RecoverComma, ) -> PResult<'a, P> { // Parse the first pattern. let first_pat = self.parse_pat(expected)?; - self.maybe_recover_unexpected_comma(first_pat.span, top_level)?; + self.maybe_recover_unexpected_comma(first_pat.span, rc)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -115,7 +115,7 @@ impl<'a> Parser<'a> { err.span_label(lo, "while parsing this or-pattern staring here"); err })?; - self.maybe_recover_unexpected_comma(pat.span, top_level)?; + self.maybe_recover_unexpected_comma(pat.span, rc)?; pats.push(pat); } let or_pattern_span = lo.to(self.prev_span); @@ -156,8 +156,8 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, top_level: TopLevel) -> PResult<'a, ()> { - if top_level == TopLevel::No || self.token != token::Comma { + fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> { + if rc == RecoverComma::No || self.token != token::Comma { return Ok(()); } @@ -207,7 +207,7 @@ impl<'a> Parser<'a> { /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { self.recover_leading_vert("only allowed in a top-level pattern"); - self.parse_pat_with_or(None, GateOr::Yes, TopLevel::No) + self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No) } /// Recover if `|` or `||` is here. -- cgit 1.4.1-3-g733a5 From c9d9616e825fecd4301beaf7bcd9115d5d7d393f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 24 Aug 2019 17:50:21 +0200 Subject: Introduce and use `Feature` type for feature gates This replaces the ad-hoc tuples used in the different feature gate files and unifies their content into a common type, leading to more readable matches and other good stuff that comes from having named fields. It also contains the description of each feature as extracted from the doc comment. --- src/libsyntax/feature_gate/accepted.rs | 16 +++++++++++++--- src/libsyntax/feature_gate/active.rs | 10 ++++++++++ src/libsyntax/feature_gate/check.rs | 33 ++++++++++++++++++--------------- src/libsyntax/feature_gate/mod.rs | 33 +++++++++++++++++++++++++++++++++ src/libsyntax/feature_gate/removed.rs | 29 ++++++++++++++++++++++++----- 5 files changed, 98 insertions(+), 23 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs index 28e4d2c073c..6c0b271c6c5 100644 --- a/src/libsyntax/feature_gate/accepted.rs +++ b/src/libsyntax/feature_gate/accepted.rs @@ -1,14 +1,24 @@ //! List of the accepted feature gates. -use crate::symbol::{Symbol, sym}; +use crate::symbol::sym; +use super::{State, Feature}; macro_rules! declare_features { ($( $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None), )+) => { /// Those language feature has since been Accepted (it was once Active) - pub const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ + pub const ACCEPTED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Accepted, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ ]; } } diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 4008b79b141..c947b09fdcb 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -65,6 +65,16 @@ macro_rules! declare_features { }; } +impl Feature { + /// Set this feature in `Features`. Panics if called on a non-active feature. + pub fn set(&self, features: &mut Features, span: Span) { + match self.state { + State::Active { set } => set(features, span), + _ => panic!("Called `set` on feature `{}` which is not `active`", self.name) + } + } +} + // If you change this, please modify `src/doc/unstable-book` as well. // // Don't ever remove anything from this list; move them to `removed.rs`. diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index d82b287b6fb..344e5fd6e46 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -1,4 +1,4 @@ -use super::active::{ACTIVE_FEATURES, Features}; +use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState}; use super::accepted::ACCEPTED_FEATURES; use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use super::builtin_attrs::{AttributeGate, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; @@ -127,17 +127,16 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: } fn find_lang_feature_issue(feature: Symbol) -> Option { - if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { - let issue = info.2; + if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { // FIXME (#28244): enforce that active features have issue numbers - // assert!(issue.is_some()) - issue + // assert!(info.issue.is_some()) + info.issue } else { // search in Accepted, Removed, or Stable Removed features let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) - .find(|t| t.0 == feature); + .find(|t| t.name == feature); match found { - Some(&(_, _, issue, _)) => issue, + Some(&Feature { issue, .. }) => issue, None => panic!("Feature `{}` is not declared anywhere", feature), } } @@ -829,14 +828,18 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], continue; } - let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); - let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); - if let Some((.., reason)) = removed.or(stable_removed) { - feature_removed(span_handler, mi.span(), *reason); - continue; + let removed = REMOVED_FEATURES.iter().find(|f| name == f.name); + let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name); + if let Some(Feature { state, .. }) = removed.or(stable_removed) { + if let FeatureState::Removed { reason } + | FeatureState::Stabilized { reason } = state + { + feature_removed(span_handler, mi.span(), *reason); + continue; + } } - if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { + if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { let since = Some(Symbol::intern(since)); features.declared_lang_features.push((name, mi.span(), since)); continue; @@ -851,8 +854,8 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } } - if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { - set(&mut features, mi.span()); + if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { + f.set(&mut features, mi.span()); features.declared_lang_features.push((name, mi.span(), None)); continue; } diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs index 97793bca1f5..1e41667ea41 100644 --- a/src/libsyntax/feature_gate/mod.rs +++ b/src/libsyntax/feature_gate/mod.rs @@ -18,6 +18,39 @@ mod active; mod builtin_attrs; mod check; +use std::fmt; +use crate::{edition::Edition, symbol::Symbol}; +use syntax_pos::Span; + +#[derive(Clone, Copy)] +pub enum State { + Accepted, + Active { set: fn(&mut Features, Span) }, + Removed { reason: Option<&'static str> }, + Stabilized { reason: Option<&'static str> }, +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + State::Accepted { .. } => write!(f, "accepted"), + State::Active { .. } => write!(f, "active"), + State::Removed { .. } => write!(f, "removed"), + State::Stabilized { .. } => write!(f, "stabilized"), + } + } +} + +#[derive(Debug, Clone)] +pub struct Feature { + state: State, + name: Symbol, + since: &'static str, + issue: Option, + edition: Option, + description: &'static str, +} + pub use active::{Features, INCOMPLETE_FEATURES}; pub use builtin_attrs::{ AttributeGate, AttributeType, GatedCfg, diff --git a/src/libsyntax/feature_gate/removed.rs b/src/libsyntax/feature_gate/removed.rs index 6494c82e122..ad7d69b3e73 100644 --- a/src/libsyntax/feature_gate/removed.rs +++ b/src/libsyntax/feature_gate/removed.rs @@ -1,14 +1,24 @@ //! List of the removed feature gates. -use crate::symbol::{Symbol, sym}; +use crate::symbol::sym; +use super::{State, Feature}; macro_rules! declare_features { ($( $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), )+) => { /// Represents unstable features which have since been removed (it was once Active) - pub const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, $reason)),+ + pub const REMOVED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Removed { reason: $reason }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ ]; }; @@ -16,8 +26,17 @@ macro_rules! declare_features { $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None), )+) => { /// Represents stable features which have since been removed (it was once Accepted) - pub const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ + pub const STABLE_REMOVED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Stabilized { reason: None }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ ]; }; } -- cgit 1.4.1-3-g733a5 From 5b7df0922ef15a8b105aceda8770faedc58ec67b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 25 Aug 2019 20:41:52 +0300 Subject: pprust: Do not print spaces before some tokens --- src/libsyntax/print/pprust.rs | 14 +++++++++++++- src/test/pretty/attr-literals.rs | 4 ++-- src/test/pretty/block-comment-wchar.pp | 5 +---- src/test/pretty/delimited-token-groups.rs | 2 +- src/test/pretty/do1.rs | 2 +- src/test/pretty/match-block-expr.rs | 2 +- src/test/ui/macros/macro-first-set.rs | 2 +- src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs | 4 ++-- src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs | 4 ++-- 9 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4dc00af4860..83a926a6217 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -152,6 +152,18 @@ pub fn to_string(f: F) -> String where printer.s.eof() } +// This makes comma-separated lists look slightly nicer, +// and also addresses a specific regression described in issue #63896. +fn tt_prepend_space(tt: &TokenTree) -> bool { + match tt { + TokenTree::Token(token) => match token.kind { + token::Comma => false, + _ => true, + } + _ => true, + } +} + fn binop_to_string(op: BinOpToken) -> &'static str { match op { token::Plus => "+", @@ -696,7 +708,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::DerefM fn print_tts(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) { for (i, tt) in tts.into_trees().enumerate() { - if i != 0 { + if i != 0 && tt_prepend_space(&tt) { self.space(); } self.print_tt(tt, convert_dollar_crate); diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs index bcd6ffaaf81..9db7e27b161 100644 --- a/src/test/pretty/attr-literals.rs +++ b/src/test/pretty/attr-literals.rs @@ -5,10 +5,10 @@ #![feature(rustc_attrs)] fn main() { - #![rustc_dummy("hi" , 1 , 2 , 1.012 , pi = 3.14 , bye , name ("John"))] + #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name ("John"))] #[rustc_dummy = 8] fn f() { } - #[rustc_dummy(1 , 2 , 3)] + #[rustc_dummy(1, 2, 3)] fn g() { } } diff --git a/src/test/pretty/block-comment-wchar.pp b/src/test/pretty/block-comment-wchar.pp index f15d7cdc44c..9317b36ba49 100644 --- a/src/test/pretty/block-comment-wchar.pp +++ b/src/test/pretty/block-comment-wchar.pp @@ -99,8 +99,5 @@ fn main() { '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}', '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', '\u{205F}', '\u{3000}']; - for c in &chars { - let ws = c.is_whitespace(); - println!("{} {}" , c , ws); - } + for c in &chars { let ws = c.is_whitespace(); println!("{} {}", c, ws); } } diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs index 768f27ad23a..7bbb7dc911f 100644 --- a/src/test/pretty/delimited-token-groups.rs +++ b/src/test/pretty/delimited-token-groups.rs @@ -5,7 +5,7 @@ macro_rules! mac { ($ ($ tt : tt) *) => () } mac! { - struct S { field1 : u8 , field2 : u16 , } impl Clone for S + struct S { field1 : u8, field2 : u16, } impl Clone for S { fn clone () -> S { diff --git a/src/test/pretty/do1.rs b/src/test/pretty/do1.rs index 7be835cb22f..233ccdb0098 100644 --- a/src/test/pretty/do1.rs +++ b/src/test/pretty/do1.rs @@ -2,4 +2,4 @@ fn f(f: F) where F: Fn(isize) { f(10) } -fn main() { f(|i| { assert_eq!(i , 10) }) } +fn main() { f(|i| { assert_eq!(i, 10) }) } diff --git a/src/test/pretty/match-block-expr.rs b/src/test/pretty/match-block-expr.rs index 0db6574b073..10903e928cd 100644 --- a/src/test/pretty/match-block-expr.rs +++ b/src/test/pretty/match-block-expr.rs @@ -2,5 +2,5 @@ fn main() { let x = match { 5 } { 1 => 5, 2 => 6, _ => 7, }; - assert_eq!(x , 7); + assert_eq!(x, 7); } diff --git a/src/test/ui/macros/macro-first-set.rs b/src/test/ui/macros/macro-first-set.rs index a21e4cd201a..34529cdaa64 100644 --- a/src/test/ui/macros/macro-first-set.rs +++ b/src/test/ui/macros/macro-first-set.rs @@ -25,7 +25,7 @@ macro_rules! foo_26444 { } fn test_26444() { - assert_eq!("a , b , c , d , e", foo_26444!(a, b; c; d, e)); + assert_eq!("a, b, c, d, e", foo_26444!(a, b; c; d, e)); assert_eq!("f", foo_26444!(; f ;)); } diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs index d81e16d9d29..f1de3709b16 100644 --- a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs +++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs @@ -17,7 +17,7 @@ pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\" , string);"); + assert_eq!(item.to_string(), "println!(\"{}\", string);"); item } @@ -31,7 +31,7 @@ pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\" , string)"); + assert_eq!(item.to_string(), "println!(\"{}\", string)"); item } diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs index 0a82cbedd77..d2180def5b7 100644 --- a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs +++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs @@ -17,7 +17,7 @@ pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\" , string);"); + assert_eq!(item.to_string(), "println!(\"{}\", string);"); item } @@ -31,7 +31,7 @@ pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\" , string)"); + assert_eq!(item.to_string(), "println!(\"{}\", string)"); item } -- cgit 1.4.1-3-g733a5 From 94e8ff4f0b94c788ec9e9a28d3aa6f87062e2966 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 24 Aug 2019 17:50:21 +0200 Subject: Refactor feature gate checking code Tries to clarify the filtering of active features and make the code more expressive. --- src/libsyntax/feature_gate/check.rs | 40 ++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 344e5fd6e46..f3a9d135125 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -732,13 +732,9 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } } - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= crate_edition { - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, crate_edition); - } - } + for feature in active_features_up_to(crate_edition) { + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, crate_edition); } // Process the edition umbrella feature-gates first, to ensure @@ -760,20 +756,17 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], let name = mi.name_or_empty(); - if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) { - if *edition <= crate_edition { + let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); + if let Some(edition) = edition { + if edition <= crate_edition { continue; } - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= *edition { - // FIXME(Manishearth) there is currently no way to set - // lib features by edition - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, *edition); - } - } + for feature in active_features_up_to(edition) { + // FIXME(Manishearth) there is currently no way to set + // lib features by edition + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, edition); } } } @@ -867,6 +860,17 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], features } +fn active_features_up_to(edition: Edition) -> impl Iterator { + ACTIVE_FEATURES.iter() + .filter(move |feature| { + if let Some(feature_edition) = feature.edition { + feature_edition <= edition + } else { + false + } + }) +} + pub fn check_crate(krate: &ast::Crate, sess: &ParseSess, features: &Features, -- cgit 1.4.1-3-g733a5 From 2bd27fbdfe309f3f6abd76f72f379247d49048b7 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 26 Aug 2019 22:14:31 +0200 Subject: parser: fix span for leading vert. --- src/libsyntax/parse/parser/pat.rs | 3 ++- src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr | 4 ++-- src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index f2e269e03ba..78c9a289b37 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -50,6 +50,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; + let leading_vert_span = self.prev_span; // Parse the possibly-or-pattern. let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; @@ -61,7 +62,7 @@ impl<'a> Parser<'a> { if gated_leading_vert { let mut or_pattern_spans = self.sess.gated_spans.or_patterns.borrow_mut(); if or_pattern_spans.is_empty() { - or_pattern_spans.push(self.prev_span); + or_pattern_spans.push(leading_vert_span); } } diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr index 83804d564f3..f520409e8ba 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr @@ -1,8 +1,8 @@ error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns-leading-for.rs:7:11 + --> $DIR/feature-gate-or_patterns-leading-for.rs:7:9 | LL | for | A in 0 {} - | ^ + | ^ | = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr index f7954ad7a8c..30fd6a1a95e 100644 --- a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr @@ -1,8 +1,8 @@ error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns-leading-let.rs:7:11 + --> $DIR/feature-gate-or_patterns-leading-let.rs:7:9 | LL | let | A; - | ^ + | ^ | = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable -- cgit 1.4.1-3-g733a5 From ec45b87957c4158934fc3f5a821594ad0686ea4e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 24 Aug 2019 21:12:13 +0300 Subject: resolve: Block expansion of a derive container until all its derives are resolved Also mark derive helpers as known as a part of the derive container's expansion instead of expansion of the derives themselves which may happen too late. --- src/librustc_metadata/decoder.rs | 4 +- src/librustc_resolve/macros.rs | 41 ++++---- src/libsyntax/ext/base.rs | 20 +++- src/libsyntax/ext/expand.rs | 114 ++++++++++++--------- src/libsyntax/ext/proc_macro.rs | 6 +- src/test/ui/derives/deriving-bounds.stderr | 24 ++--- .../issue-43106-gating-of-derive-2.stderr | 4 +- .../feature-gate/issue-43106-gating-of-derive.rs | 3 - .../issue-43106-gating-of-derive.stderr | 16 +-- src/test/ui/issues/issue-36617.rs | 1 + src/test/ui/issues/issue-36617.stderr | 10 +- src/test/ui/proc-macro/derive-helper-configured.rs | 18 ++++ src/test/ui/proc-macro/derive-helper-shadowing.rs | 3 +- .../ui/proc-macro/derive-helper-shadowing.stderr | 8 +- src/test/ui/proc-macro/resolve-error.stderr | 76 +++++++------- 15 files changed, 195 insertions(+), 153 deletions(-) create mode 100644 src/test/ui/proc-macro/derive-helper-configured.rs (limited to 'src/libsyntax') diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5b9cb966af2..7d2414f9a1d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -538,9 +538,7 @@ impl<'a, 'tcx> CrateMetadata { attributes.iter().cloned().map(Symbol::intern).collect::>(); ( trait_name, - SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { - client, attrs: helper_attrs.clone() - })), + SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { client })), helper_attrs, ) } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 719167eb057..20418633dc6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -13,7 +13,7 @@ use rustc::{ty, lint, span_bug}; use syntax::ast::{self, NodeId, Ident}; use syntax::attr::StabilityLevel; use syntax::edition::Edition; -use syntax::ext::base::{self, Indeterminate, SpecialDerives}; +use syntax::ext::base::{self, InvocationRes, Indeterminate, SpecialDerives}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind}; @@ -142,7 +142,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_macro_invocation( &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool - ) -> Result>, Indeterminate> { + ) -> Result { let invoc_id = invoc.expansion_data.id; let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) { Some(parent_scope) => *parent_scope, @@ -165,25 +165,24 @@ impl<'a> base::Resolver for Resolver<'a> { InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, &[][..], false), InvocationKind::DeriveContainer { ref derives, .. } => { - // Block expansion of derives in the container until we know whether one of them - // is a built-in `Copy`. Skip the resolution if there's only one derive - either - // it's not a `Copy` and we don't need to do anything, or it's a `Copy` and it - // will automatically knows about itself. - let mut result = Ok(None); - if derives.len() > 1 { - for path in derives { - match self.resolve_macro_path(path, Some(MacroKind::Derive), - &parent_scope, true, force) { - Ok((Some(ref ext), _)) if ext.is_derive_copy => { - self.add_derives(invoc_id, SpecialDerives::COPY); - return Ok(None); - } - Err(Determinacy::Undetermined) => result = Err(Indeterminate), - _ => {} - } - } + // Block expansion of the container until we resolve all derives in it. + // This is required for two reasons: + // - Derive helper attributes are in scope for the item to which the `#[derive]` + // is applied, so they have to be produced by the container's expansion rather + // than by individual derives. + // - Derives in the container need to know whether one of them is a built-in `Copy`. + // FIXME: Try to avoid repeated resolutions for derives here and in expansion. + let mut exts = Vec::new(); + for path in derives { + exts.push(match self.resolve_macro_path( + path, Some(MacroKind::Derive), &parent_scope, true, force + ) { + Ok((Some(ext), _)) => ext, + Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive), + Err(Determinacy::Undetermined) => return Err(Indeterminate), + }) } - return result; + return Ok(InvocationRes::DeriveContainer(exts)); } }; @@ -203,7 +202,7 @@ impl<'a> base::Resolver for Resolver<'a> { self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id); } - Ok(Some(ext)) + Ok(InvocationRes::Single(ext)) } fn check_unused_macros(&self) { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a63c4181d5e..f0397558a1d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -11,6 +11,7 @@ use crate::ptr::P; use crate::symbol::{kw, sym, Ident, Symbol}; use crate::{ThinVec, MACRO_ARGUMENTS}; use crate::tokenstream::{self, TokenStream, TokenTree}; +use crate::visit::Visitor; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; @@ -72,6 +73,17 @@ impl Annotatable { } } + pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { + match self { + Annotatable::Item(item) => visitor.visit_item(item), + Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item), + Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item), + Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item), + Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt), + Annotatable::Expr(expr) => visitor.visit_expr(expr), + } + } + pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, @@ -637,6 +649,12 @@ impl SyntaxExtension { pub type NamedSyntaxExtension = (Name, SyntaxExtension); +/// Result of resolving a macro invocation. +pub enum InvocationRes { + Single(Lrc), + DeriveContainer(Vec>), +} + /// Error type that denotes indeterminacy. pub struct Indeterminate; @@ -664,7 +682,7 @@ pub trait Resolver { fn resolve_macro_invocation( &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool - ) -> Result>, Indeterminate>; + ) -> Result; fn check_unused_macros(&self); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a6b56e4d597..7b4a5167446 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -4,7 +4,7 @@ use crate::attr::{self, HasAttrs}; use crate::source_map::respan; use crate::config::StripUnconfigured; use crate::ext::base::*; -use crate::ext::proc_macro::collect_derives; +use crate::ext::proc_macro::{collect_derives, MarkAttrs}; use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind}; use crate::ext::tt::macro_rules::annotate_err_with_kind; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; @@ -307,10 +307,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let eager_expansion_root = if self.monotonic { invoc.expansion_data.id } else { orig_expansion_data.id }; - let ext = match self.cx.resolver.resolve_macro_invocation( + let res = match self.cx.resolver.resolve_macro_invocation( &invoc, eager_expansion_root, force ) { - Ok(ext) => ext, + Ok(res) => res, Err(Indeterminate) => { undetermined_invocations.push(invoc); continue @@ -322,54 +322,72 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion = invoc.expansion_data.clone(); // FIXME(jseyfried): Refactor out the following logic - let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - let fragment = self.expand_invoc(invoc, &ext.kind); - self.collect_invocations(fragment, &[]) - } else if let InvocationKind::DeriveContainer { derives: traits, item } = invoc.kind { - if !item.derive_allowed() { - let attr = attr::find_by_name(item.attrs(), sym::derive) - .expect("`derive` attribute should exist"); - let span = attr.span; - let mut err = self.cx.mut_span_err(span, - "`derive` may only be applied to \ - structs, enums and unions"); - if let ast::AttrStyle::Inner = attr.style { - let trait_list = traits.iter() - .map(|t| t.to_string()).collect::>(); - let suggestion = format!("#[derive({})]", trait_list.join(", ")); - err.span_suggestion( - span, "try an outer attribute", suggestion, - // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT - Applicability::MaybeIncorrect - ); - } - err.emit(); + let (expanded_fragment, new_invocations) = match res { + InvocationRes::Single(ext) => { + let fragment = self.expand_invoc(invoc, &ext.kind); + self.collect_invocations(fragment, &[]) } + InvocationRes::DeriveContainer(exts) => { + let (derives, item) = match invoc.kind { + InvocationKind::DeriveContainer { derives, item } => (derives, item), + _ => unreachable!(), + }; + if !item.derive_allowed() { + let attr = attr::find_by_name(item.attrs(), sym::derive) + .expect("`derive` attribute should exist"); + let span = attr.span; + let mut err = self.cx.mut_span_err(span, + "`derive` may only be applied to structs, enums and unions"); + if let ast::AttrStyle::Inner = attr.style { + let trait_list = derives.iter() + .map(|t| t.to_string()).collect::>(); + let suggestion = format!("#[derive({})]", trait_list.join(", ")); + err.span_suggestion( + span, "try an outer attribute", suggestion, + // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT + Applicability::MaybeIncorrect + ); + } + err.emit(); + } - let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); - let derive_placeholders = - all_derive_placeholders.entry(invoc.expansion_data.id).or_default(); - - derive_placeholders.reserve(traits.len()); - invocations.reserve(traits.len()); - for path in traits { - let expn_id = ExpnId::fresh(None); - derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id)); - invocations.push(Invocation { - kind: InvocationKind::Derive { path, item: item.clone() }, - fragment_kind: invoc.fragment_kind, - expansion_data: ExpansionData { - id: expn_id, - ..invoc.expansion_data.clone() - }, - }); + let mut item = self.fully_configure(item); + item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); + let mut helper_attrs = Vec::new(); + let mut has_copy = false; + for ext in exts { + helper_attrs.extend(&ext.helper_attrs); + has_copy |= ext.is_derive_copy; + } + // Mark derive helpers inside this item as known and used. + // FIXME: This is a hack, derive helpers should be integrated with regular name + // resolution instead. For example, helpers introduced by a derive container + // can be in scope for all code produced by that container's expansion. + item.visit_with(&mut MarkAttrs(&helper_attrs)); + if has_copy { + self.cx.resolver.add_derives(invoc.expansion_data.id, SpecialDerives::COPY); + } + + let derive_placeholders = + all_derive_placeholders.entry(invoc.expansion_data.id).or_default(); + derive_placeholders.reserve(derives.len()); + invocations.reserve(derives.len()); + for path in derives { + let expn_id = ExpnId::fresh(None); + derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id)); + invocations.push(Invocation { + kind: InvocationKind::Derive { path, item: item.clone() }, + fragment_kind: invoc.fragment_kind, + expansion_data: ExpansionData { + id: expn_id, + ..invoc.expansion_data.clone() + }, + }); + } + let fragment = invoc.fragment_kind + .expect_from_annotatables(::std::iter::once(item)); + self.collect_invocations(fragment, derive_placeholders) } - let fragment = invoc.fragment_kind - .expect_from_annotatables(::std::iter::once(item)); - self.collect_invocations(fragment, derive_placeholders) - } else { - unreachable!() }; if expanded_fragments.len() < depth { diff --git a/src/libsyntax/ext/proc_macro.rs b/src/libsyntax/ext/proc_macro.rs index c17b6f6b424..4a44c9a9f1f 100644 --- a/src/libsyntax/ext/proc_macro.rs +++ b/src/libsyntax/ext/proc_macro.rs @@ -78,7 +78,6 @@ pub struct ProcMacroDerive { pub client: proc_macro::bridge::client::Client< fn(proc_macro::TokenStream) -> proc_macro::TokenStream, >, - pub attrs: Vec, } impl MultiItemModifier for ProcMacroDerive { @@ -111,9 +110,6 @@ impl MultiItemModifier for ProcMacroDerive { } } - // Mark attributes as known, and used. - MarkAttrs(&self.attrs).visit_item(&item); - let token = token::Interpolated(Lrc::new(token::NtItem(item))); let input = tokenstream::TokenTree::token(token, DUMMY_SP).into(); @@ -164,7 +160,7 @@ impl MultiItemModifier for ProcMacroDerive { } } -struct MarkAttrs<'a>(&'a [ast::Name]); +crate struct MarkAttrs<'a>(crate &'a [ast::Name]); impl<'a> Visitor<'a> for MarkAttrs<'a> { fn visit_attribute(&mut self, attr: &Attribute) { diff --git a/src/test/ui/derives/deriving-bounds.stderr b/src/test/ui/derives/deriving-bounds.stderr index 99976da72da..b18df351181 100644 --- a/src/test/ui/derives/deriving-bounds.stderr +++ b/src/test/ui/derives/deriving-bounds.stderr @@ -1,15 +1,3 @@ -error: cannot find derive macro `Send` in this scope - --> $DIR/deriving-bounds.rs:1:10 - | -LL | #[derive(Send)] - | ^^^^ - | -note: unsafe traits like `Send` should be implemented explicitly - --> $DIR/deriving-bounds.rs:1:10 - | -LL | #[derive(Send)] - | ^^^^ - error: cannot find derive macro `Sync` in this scope --> $DIR/deriving-bounds.rs:5:10 | @@ -22,5 +10,17 @@ note: unsafe traits like `Sync` should be implemented explicitly LL | #[derive(Sync)] | ^^^^ +error: cannot find derive macro `Send` in this scope + --> $DIR/deriving-bounds.rs:1:10 + | +LL | #[derive(Send)] + | ^^^^ + | +note: unsafe traits like `Send` should be implemented explicitly + --> $DIR/deriving-bounds.rs:1:10 + | +LL | #[derive(Send)] + | ^^^^ + error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr index be3536aa789..f14591c85e6 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr @@ -1,5 +1,5 @@ error: cannot find derive macro `x3300` in this scope - --> $DIR/issue-43106-gating-of-derive-2.rs:4:14 + --> $DIR/issue-43106-gating-of-derive-2.rs:12:14 | LL | #[derive(x3300)] | ^^^^^ @@ -11,7 +11,7 @@ LL | #[derive(x3300)] | ^^^^^ error: cannot find derive macro `x3300` in this scope - --> $DIR/issue-43106-gating-of-derive-2.rs:12:14 + --> $DIR/issue-43106-gating-of-derive-2.rs:4:14 | LL | #[derive(x3300)] | ^^^^^ diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs b/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs index 13974129884..c5d9e0db4d3 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs @@ -1,9 +1,6 @@ // `#![derive]` raises errors when it occurs at contexts other than ADT // definitions. -#![derive(Debug)] -//~^ ERROR `derive` may only be applied to structs, enums and unions - #[derive(Debug)] //~^ ERROR `derive` may only be applied to structs, enums and unions mod derive { diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr index 25f160983d3..db29a2bddd3 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr @@ -1,38 +1,32 @@ error: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:4:1 | -LL | #![derive(Debug)] - | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` - -error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:7:1 - | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:10:17 + --> $DIR/issue-43106-gating-of-derive.rs:7:17 | LL | mod inner { #![derive(Debug)] } | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:13:5 + --> $DIR/issue-43106-gating-of-derive.rs:10:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:26:5 + --> $DIR/issue-43106-gating-of-derive.rs:23:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:30:5 + --> $DIR/issue-43106-gating-of-derive.rs:27:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/issues/issue-36617.rs b/src/test/ui/issues/issue-36617.rs index 87092689a28..1102f3c4640 100644 --- a/src/test/ui/issues/issue-36617.rs +++ b/src/test/ui/issues/issue-36617.rs @@ -1,3 +1,4 @@ #![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions + //~| ERROR cannot determine resolution for the derive macro `Copy` fn main() {} diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/issues/issue-36617.stderr index 296fec46d80..b5db98f306b 100644 --- a/src/test/ui/issues/issue-36617.stderr +++ b/src/test/ui/issues/issue-36617.stderr @@ -4,5 +4,13 @@ error: `derive` may only be applied to structs, enums and unions LL | #![derive(Copy)] | ^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Copy)]` -error: aborting due to previous error +error: cannot determine resolution for the derive macro `Copy` + --> $DIR/issue-36617.rs:1:11 + | +LL | #![derive(Copy)] + | ^^^^ + | + = note: import resolution is stuck, try simplifying macro imports + +error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/derive-helper-configured.rs b/src/test/ui/proc-macro/derive-helper-configured.rs new file mode 100644 index 00000000000..243cf685e81 --- /dev/null +++ b/src/test/ui/proc-macro/derive-helper-configured.rs @@ -0,0 +1,18 @@ +// Derive helpers are resolved successfully inside `cfg_attr`. + +// check-pass +// compile-flats:--cfg TRUE +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +#[cfg_attr(TRUE, empty_helper)] +#[derive(Empty)] +#[cfg_attr(TRUE, empty_helper)] +struct S { + #[cfg_attr(TRUE, empty_helper)] + field: u8, +} + +fn main() {} diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.rs b/src/test/ui/proc-macro/derive-helper-shadowing.rs index 59ba1390e13..21af4093a03 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.rs +++ b/src/test/ui/proc-macro/derive-helper-shadowing.rs @@ -19,7 +19,8 @@ struct S { struct U; mod inner { - #[empty_helper] //~ ERROR cannot find attribute macro `empty_helper` in this scope + // FIXME No ambiguity, attributes in non-macro positions are not resolved properly + #[empty_helper] struct V; } diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr index 149f6eef443..2ba517ce29e 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr +++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr @@ -1,9 +1,3 @@ -error: cannot find attribute macro `empty_helper` in this scope - --> $DIR/derive-helper-shadowing.rs:22:15 - | -LL | #[empty_helper] - | ^^^^^^^^^^^^ - error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name) --> $DIR/derive-helper-shadowing.rs:8:3 | @@ -22,6 +16,6 @@ LL | use test_macros::empty_attr as empty_helper; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use `crate::empty_helper` to refer to this attribute macro unambiguously -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/proc-macro/resolve-error.stderr b/src/test/ui/proc-macro/resolve-error.stderr index 3c9b2baacbd..2a5f2b88381 100644 --- a/src/test/ui/proc-macro/resolve-error.stderr +++ b/src/test/ui/proc-macro/resolve-error.stderr @@ -1,32 +1,26 @@ -error: cannot find derive macro `FooWithLongNan` in this scope - --> $DIR/resolve-error.rs:22:10 - | -LL | #[derive(FooWithLongNan)] - | ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName` - -error: cannot find attribute macro `attr_proc_macra` in this scope - --> $DIR/resolve-error.rs:27:3 +error: cannot find macro `bang_proc_macrp!` in this scope + --> $DIR/resolve-error.rs:56:5 | -LL | #[attr_proc_macra] - | ^^^^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `attr_proc_macro` +LL | bang_proc_macrp!(); + | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro` -error: cannot find attribute macro `FooWithLongNan` in this scope - --> $DIR/resolve-error.rs:31:3 +error: cannot find macro `Dlona!` in this scope + --> $DIR/resolve-error.rs:53:5 | -LL | #[FooWithLongNan] - | ^^^^^^^^^^^^^^ +LL | Dlona!(); + | ^^^^^ -error: cannot find derive macro `Dlone` in this scope - --> $DIR/resolve-error.rs:34:10 +error: cannot find macro `attr_proc_macra!` in this scope + --> $DIR/resolve-error.rs:50:5 | -LL | #[derive(Dlone)] - | ^^^^^ help: a derive macro with a similar name exists: `Clone` +LL | attr_proc_macra!(); + | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac` -error: cannot find derive macro `Dlona` in this scope - --> $DIR/resolve-error.rs:38:10 +error: cannot find macro `FooWithLongNama!` in this scope + --> $DIR/resolve-error.rs:47:5 | -LL | #[derive(Dlona)] - | ^^^^^ help: a derive macro with a similar name exists: `Clona` +LL | FooWithLongNama!(); + | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `FooWithLongNam` error: cannot find derive macro `attr_proc_macra` in this scope --> $DIR/resolve-error.rs:42:10 @@ -34,29 +28,35 @@ error: cannot find derive macro `attr_proc_macra` in this scope LL | #[derive(attr_proc_macra)] | ^^^^^^^^^^^^^^^ -error: cannot find macro `FooWithLongNama!` in this scope - --> $DIR/resolve-error.rs:47:5 +error: cannot find derive macro `Dlona` in this scope + --> $DIR/resolve-error.rs:38:10 | -LL | FooWithLongNama!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `FooWithLongNam` +LL | #[derive(Dlona)] + | ^^^^^ help: a derive macro with a similar name exists: `Clona` -error: cannot find macro `attr_proc_macra!` in this scope - --> $DIR/resolve-error.rs:50:5 +error: cannot find derive macro `Dlone` in this scope + --> $DIR/resolve-error.rs:34:10 | -LL | attr_proc_macra!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac` +LL | #[derive(Dlone)] + | ^^^^^ help: a derive macro with a similar name exists: `Clone` -error: cannot find macro `Dlona!` in this scope - --> $DIR/resolve-error.rs:53:5 +error: cannot find attribute macro `FooWithLongNan` in this scope + --> $DIR/resolve-error.rs:31:3 | -LL | Dlona!(); - | ^^^^^ +LL | #[FooWithLongNan] + | ^^^^^^^^^^^^^^ -error: cannot find macro `bang_proc_macrp!` in this scope - --> $DIR/resolve-error.rs:56:5 +error: cannot find attribute macro `attr_proc_macra` in this scope + --> $DIR/resolve-error.rs:27:3 | -LL | bang_proc_macrp!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro` +LL | #[attr_proc_macra] + | ^^^^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `attr_proc_macro` + +error: cannot find derive macro `FooWithLongNan` in this scope + --> $DIR/resolve-error.rs:22:10 + | +LL | #[derive(FooWithLongNan)] + | ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName` error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 52c62eaae42ebc0efe370848a142c2858ac7fffc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 20 Aug 2019 21:22:32 +0300 Subject: Respect attributes on proc macro definitions --- src/librustc_metadata/decoder.rs | 18 +++--- src/libsyntax/ext/base.rs | 67 ++++++++++++++++++++- src/libsyntax/ext/tt/macro_rules.rs | 70 ++++------------------ .../ui/proc-macro/attributes-on-definitions.rs | 12 ++++ .../ui/proc-macro/attributes-on-definitions.stderr | 8 +++ .../auxiliary/attributes-on-definitions.rs | 23 +++++++ 6 files changed, 131 insertions(+), 67 deletions(-) create mode 100644 src/test/ui/proc-macro/attributes-on-definitions.rs create mode 100644 src/test/ui/proc-macro/attributes-on-definitions.stderr create mode 100644 src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs (limited to 'src/libsyntax') diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5b9cb966af2..fffeee82d8d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -530,7 +530,6 @@ impl<'a, 'tcx> CrateMetadata { id: DefIndex, sess: &Session) -> FullProcMacro { - let raw_macro = self.raw_proc_macro(id); let (name, kind, helper_attrs) = match *raw_macro { ProcMacro::CustomDerive { trait_name, attributes, client } => { @@ -551,16 +550,19 @@ impl<'a, 'tcx> CrateMetadata { name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new() ) }; - - let span = self.get_span(id, sess); + let name = Symbol::intern(name); FullProcMacro { - name: Symbol::intern(name), - ext: Lrc::new(SyntaxExtension { - span, + name, + ext: Lrc::new(SyntaxExtension::new( + &sess.parse_sess, + kind, + self.get_span(id, sess), helper_attrs, - ..SyntaxExtension::default(kind, root.edition) - }) + root.edition, + name, + &self.get_attributes(&self.entry(id), sess), + )), } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a63c4181d5e..10ff1b17285 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,11 +1,11 @@ use crate::ast::{self, NodeId, Attribute, Name, PatKind}; -use crate::attr::{HasAttrs, Stability, Deprecation}; +use crate::attr::{self, HasAttrs, Stability, Deprecation}; use crate::source_map::SourceMap; use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; use crate::ext::hygiene::{ExpnId, Transparency}; use crate::mut_visit::{self, MutVisitor}; -use crate::parse::{self, parser, DirectoryOwnership}; +use crate::parse::{self, parser, ParseSess, DirectoryOwnership}; use crate::parse::token; use crate::ptr::P; use crate::symbol::{kw, sym, Ident, Symbol}; @@ -601,6 +601,69 @@ impl SyntaxExtension { } } + /// Constructs a syntax extension with the given properties + /// and other properties converted from attributes. + pub fn new( + sess: &ParseSess, + kind: SyntaxExtensionKind, + span: Span, + helper_attrs: Vec, + edition: Edition, + name: Name, + attrs: &[ast::Attribute], + ) -> SyntaxExtension { + let allow_internal_unstable = + attr::find_by_name(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 mut local_inner_macros = false; + if let Some(macro_export) = attr::find_by_name(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); + } + } + + let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro); + + SyntaxExtension { + kind, + span, + allow_internal_unstable, + allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe), + local_inner_macros, + stability: attr::find_stability(&sess, attrs, span), + deprecation: attr::find_deprecation(&sess, attrs, span), + helper_attrs, + edition, + is_builtin, + is_derive_copy: is_builtin && name == sym::Copy, + } + } + pub fn dummy_bang(edition: Edition) -> SyntaxExtension { fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree]) -> Box { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 37cb8467ff5..46ffa52f7f5 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -1,3 +1,5 @@ +use crate::ast; +use crate::attr::{self, TransparencyError}; use crate::edition::Edition; use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind}; @@ -15,7 +17,6 @@ use crate::parse::token::{self, NtTT, Token}; use crate::parse::{Directory, ParseSess}; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; -use crate::{ast, attr, attr::TransparencyError}; use errors::{DiagnosticBuilder, FatalError}; use log::debug; @@ -290,6 +291,7 @@ pub fn compile( def: &ast::Item, edition: Edition, ) -> SyntaxExtension { + let diag = &sess.span_diagnostic; let lhs_nm = ast::Ident::new(sym::lhs, def.span); let rhs_nm = ast::Ident::new(sym::rhs, def.span); let tt_spec = ast::Ident::new(sym::tt, def.span); @@ -423,13 +425,9 @@ pub fn compile( let (transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => - sess.span_diagnostic.span_err( - span, &format!("unknown macro transparency: `{}`", value) - ), + diag.span_err(span, &format!("unknown macro transparency: `{}`", value)), Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => - sess.span_diagnostic.span_err( - vec![old_span, new_span], "multiple macro transparency attributes" - ), + diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes"), None => {} } @@ -437,57 +435,15 @@ pub fn compile( name: def.ident, span: def.span, transparency, lhses, rhses, valid }); - 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 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); - } - } - - let is_builtin = attr::contains_name(&def.attrs, sym::rustc_builtin_macro); - - SyntaxExtension { - kind: SyntaxExtensionKind::LegacyBang(expander), - span: def.span, - allow_internal_unstable, - allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe), - local_inner_macros, - stability: attr::find_stability(&sess, &def.attrs, def.span), - deprecation: attr::find_deprecation(&sess, &def.attrs, def.span), - helper_attrs: Vec::new(), + SyntaxExtension::new( + sess, + SyntaxExtensionKind::LegacyBang(expander), + def.span, + Vec::new(), edition, - is_builtin, - is_derive_copy: is_builtin && def.ident.name == sym::Copy, - } + def.ident.name, + &def.attrs, + ) } fn check_lhs_nt_follows( diff --git a/src/test/ui/proc-macro/attributes-on-definitions.rs b/src/test/ui/proc-macro/attributes-on-definitions.rs new file mode 100644 index 00000000000..055781d2c60 --- /dev/null +++ b/src/test/ui/proc-macro/attributes-on-definitions.rs @@ -0,0 +1,12 @@ +// check-pass +// aux-build:attributes-on-definitions.rs + +#![forbid(unsafe_code)] + +extern crate attributes_on_definitions; + +attributes_on_definitions::with_attrs!(); +//~^ WARN use of deprecated item +// No errors about the use of unstable and unsafe code inside the macro. + +fn main() {} diff --git a/src/test/ui/proc-macro/attributes-on-definitions.stderr b/src/test/ui/proc-macro/attributes-on-definitions.stderr new file mode 100644 index 00000000000..c61e043b229 --- /dev/null +++ b/src/test/ui/proc-macro/attributes-on-definitions.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated item 'attributes_on_definitions::with_attrs': test + --> $DIR/attributes-on-definitions.rs:8:1 + | +LL | attributes_on_definitions::with_attrs!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs b/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs new file mode 100644 index 00000000000..93a339840d6 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs @@ -0,0 +1,23 @@ +// force-host +// no-prefer-dynamic + +#![feature(allow_internal_unsafe)] +#![feature(allow_internal_unstable)] + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +#[allow_internal_unstable(proc_macro_internals)] +#[allow_internal_unsafe] +#[deprecated(since = "1.0.0", note = "test")] +pub fn with_attrs(_: TokenStream) -> TokenStream { + " + extern crate proc_macro; + use ::proc_macro::bridge; + + fn contains_unsafe() { unsafe {} } + ".parse().unwrap() +} -- cgit 1.4.1-3-g733a5 From c476b55e528ce854b6198de5bcfdd20b08440c9d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 20 Aug 2019 23:35:03 +0300 Subject: proc_macro: Update `Span::def_site` to use the proc macro definition location Which is no longer dummy and is available from metadata now. --- src/libsyntax/ext/proc_macro_server.rs | 7 +- src/libsyntax/parse/parser.rs | 9 +- .../ui/macros/auxiliary/proc_macro_sequence.rs | 20 +++- src/test/ui/macros/same-sequence-span.stderr | 12 +- src/test/ui/proc-macro/multispan.stderr | 133 ++++++++++++++++----- src/test/ui/proc-macro/three-equals.stderr | 19 ++- 6 files changed, 151 insertions(+), 49 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index b1bbd2aaac9..1a26b17dac7 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -360,12 +360,11 @@ pub(crate) struct Rustc<'a> { impl<'a> Rustc<'a> { pub fn new(cx: &'a ExtCtxt<'_>) -> Self { - // No way to determine def location for a proc macro right now, so use call location. - let location = cx.current_expansion.id.expn_data().call_site; + let expn_data = cx.current_expansion.id.expn_data(); Rustc { sess: cx.parse_sess, - def_site: cx.with_def_site_ctxt(location), - call_site: cx.with_call_site_ctxt(location), + def_site: cx.with_def_site_ctxt(expn_data.def_site), + call_site: cx.with_call_site_ctxt(expn_data.call_site), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 89725d8b339..47243b1ac56 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -375,10 +375,11 @@ impl<'a> Parser<'a> { if let Some(directory) = directory { parser.directory = directory; } else if !parser.token.span.is_dummy() { - if let FileName::Real(mut path) = - sess.source_map().span_to_unmapped_path(parser.token.span) { - path.pop(); - parser.directory.path = Cow::from(path); + if let Some(FileName::Real(path)) = + &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path { + if let Some(directory_path) = path.parent() { + parser.directory.path = Cow::from(directory_path.to_path_buf()); + } } } diff --git a/src/test/ui/macros/auxiliary/proc_macro_sequence.rs b/src/test/ui/macros/auxiliary/proc_macro_sequence.rs index b50ed7ca92a..c460db36f1a 100644 --- a/src/test/ui/macros/auxiliary/proc_macro_sequence.rs +++ b/src/test/ui/macros/auxiliary/proc_macro_sequence.rs @@ -6,7 +6,7 @@ extern crate proc_macro; -use proc_macro::{quote, Span, TokenStream}; +use proc_macro::{quote, Span, TokenStream, TokenTree}; fn assert_same_span(a: Span, b: Span) { assert_eq!(a.start(), b.start()); @@ -24,12 +24,22 @@ pub fn make_foo(_: TokenStream) -> TokenStream { }; // Check that all spans are equal. - let mut span = None; + // FIXME: `quote!` gives def-site spans to idents and literals, + // but leaves (default) call-site spans on groups and punctuation. + let mut span_call = None; + let mut span_def = None; for tt in result.clone() { - match span { - None => span = Some(tt.span()), - Some(span) => assert_same_span(tt.span(), span), + match tt { + TokenTree::Ident(..) | TokenTree::Literal(..) => match span_def { + None => span_def = Some(tt.span()), + Some(span) => assert_same_span(tt.span(), span), + } + TokenTree::Punct(..) | TokenTree::Group(..) => match span_call { + None => span_call = Some(tt.span()), + Some(span) => assert_same_span(tt.span(), span), + } } + } result diff --git a/src/test/ui/macros/same-sequence-span.stderr b/src/test/ui/macros/same-sequence-span.stderr index 250773a1853..0eef4a2a678 100644 --- a/src/test/ui/macros/same-sequence-span.stderr +++ b/src/test/ui/macros/same-sequence-span.stderr @@ -17,11 +17,15 @@ LL | $(= $z:tt)* error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments --> $DIR/same-sequence-span.rs:20:1 | -LL | proc_macro_sequence::make_foo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | proc_macro_sequence::make_foo!(); + | ^-------------------------------- + | | + | _in this macro invocation | | - | not allowed after `expr` fragments - | in this macro invocation +LL | | +LL | | +LL | | fn main() {} +... | | = note: allowed there are: `=>`, `,` or `;` diff --git a/src/test/ui/proc-macro/multispan.stderr b/src/test/ui/proc-macro/multispan.stderr index a0c1f9cd5c0..e7f705c7feb 100644 --- a/src/test/ui/proc-macro/multispan.stderr +++ b/src/test/ui/proc-macro/multispan.stderr @@ -1,8 +1,19 @@ error: hello to you, too! - --> $DIR/multispan.rs:14:5 - | -LL | hello!(hi); - | ^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:14:5 + | +LL | hello!(hi); + | ----------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:14:12 @@ -11,10 +22,21 @@ LL | hello!(hi); | ^^ error: hello to you, too! - --> $DIR/multispan.rs:17:5 - | -LL | hello!(hi hi); - | ^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:17:5 + | +LL | hello!(hi hi); + | -------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:17:12 @@ -23,10 +45,21 @@ LL | hello!(hi hi); | ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:20:5 - | -LL | hello!(hi hi hi); - | ^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:20:5 + | +LL | hello!(hi hi hi); + | ----------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:20:12 @@ -35,10 +68,21 @@ LL | hello!(hi hi hi); | ^^ ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:23:5 - | -LL | hello!(hi hey hi yo hi beep beep hi hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:23:5 + | +LL | hello!(hi hey hi yo hi beep beep hi hi); + | ---------------------------------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:23:12 @@ -47,10 +91,21 @@ LL | hello!(hi hey hi yo hi beep beep hi hi); | ^^ ^^ ^^ ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:24:5 - | -LL | hello!(hi there, hi how are you? hi... hi.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:24:5 + | +LL | hello!(hi there, hi how are you? hi... hi.); + | -------------------------------------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:24:12 @@ -59,10 +114,21 @@ LL | hello!(hi there, hi how are you? hi... hi.); | ^^ ^^ ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:25:5 - | -LL | hello!(whoah. hi di hi di ho); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:25:5 + | +LL | hello!(whoah. hi di hi di ho); + | ------------------------------ in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:25:19 @@ -71,10 +137,21 @@ LL | hello!(whoah. hi di hi di ho); | ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:26:5 - | -LL | hello!(hi good hi and good bye); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:26:5 + | +LL | hello!(hi good hi and good bye); + | -------------------------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:26:12 diff --git a/src/test/ui/proc-macro/three-equals.stderr b/src/test/ui/proc-macro/three-equals.stderr index 0a6cbe13098..0698b0f4754 100644 --- a/src/test/ui/proc-macro/three-equals.stderr +++ b/src/test/ui/proc-macro/three-equals.stderr @@ -1,8 +1,19 @@ error: found 2 equal signs, need exactly 3 - --> $DIR/three-equals.rs:15:5 - | -LL | three_equals!(==); - | ^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/three-equals.rs:42:1 + | +LL | / pub fn three_equals(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | return TokenStream::new(); +... | +LL | | "3".parse().unwrap() +LL | | } + | |_^ + | + ::: $DIR/three-equals.rs:15:5 + | +LL | three_equals!(==); + | ------------------ in this macro invocation | = help: input must be: `===` -- cgit 1.4.1-3-g733a5 From 5cc1559c600f34f534fa3e0328ca1c2659562229 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 27 Aug 2019 10:14:07 +0200 Subject: token: refactor with is_non_raw_ident_where. --- src/libsyntax/parse/token.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 1865f925165..dfea34c331a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -409,7 +409,7 @@ impl Token { crate fn expect_lit(&self) -> Lit { match self.kind { Literal(lit) => lit, - _=> panic!("`expect_lit` called on non-literal"), + _ => panic!("`expect_lit` called on non-literal"), } } @@ -457,6 +457,7 @@ impl Token { pub fn is_ident(&self) -> bool { self.ident().is_some() } + /// Returns `true` if the token is a lifetime. crate fn is_lifetime(&self) -> bool { self.lifetime().is_some() @@ -508,45 +509,38 @@ impl Token { /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: Symbol) -> bool { - self.ident().map(|(id, is_raw)| id.name == kw && !is_raw).unwrap_or(false) + self.is_non_raw_ident_where(|id| id.name == kw) } crate fn is_path_segment_keyword(&self) -> bool { - match self.ident() { - Some((id, false)) => id.is_path_segment_keyword(), - _ => false, - } + self.is_non_raw_ident_where(ast::Ident::is_path_segment_keyword) } // Returns true for reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. crate fn is_special_ident(&self) -> bool { - match self.ident() { - Some((id, false)) => id.is_special(), - _ => false, - } + self.is_non_raw_ident_where(ast::Ident::is_special) } /// Returns `true` if the token is a keyword used in the language. crate fn is_used_keyword(&self) -> bool { - match self.ident() { - Some((id, false)) => id.is_used_keyword(), - _ => false, - } + self.is_non_raw_ident_where(ast::Ident::is_used_keyword) } /// Returns `true` if the token is a keyword reserved for possible future use. crate fn is_unused_keyword(&self) -> bool { - match self.ident() { - Some((id, false)) => id.is_unused_keyword(), - _ => false, - } + self.is_non_raw_ident_where(ast::Ident::is_unused_keyword) } /// Returns `true` if the token is either a special identifier or a keyword. pub fn is_reserved_ident(&self) -> bool { + self.is_non_raw_ident_where(ast::Ident::is_reserved) + } + + /// Returns `true` if the token is a non-raw identifier for which `pred` holds. + fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool { match self.ident() { - Some((id, false)) => id.is_reserved(), + Some((id, false)) => pred(id), _ => false, } } -- cgit 1.4.1-3-g733a5 From e49b9581baba9d89519d17ac0d8400b6ae77e754 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 27 Aug 2019 10:21:41 +0200 Subject: Simplify with Symbol/Token::is_book_lit. --- src/libsyntax/parse/literal.rs | 4 ++-- src/libsyntax/parse/parser/path.rs | 2 +- src/libsyntax/parse/token.rs | 11 +++++++---- src/libsyntax_pos/symbol.rs | 5 +++++ 4 files changed, 15 insertions(+), 7 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index 6409acba573..36233de3cfb 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -104,7 +104,7 @@ impl LitKind { Ok(match kind { token::Bool => { - assert!(symbol == kw::True || symbol == kw::False); + assert!(symbol.is_bool_lit()); LitKind::Bool(symbol == kw::True) } token::Byte => return unescape_byte(&symbol.as_str()) @@ -261,7 +261,7 @@ impl Lit { /// Converts arbitrary token into an AST literal. crate fn from_token(token: &Token) -> Result { let lit = match token.kind { - token::Ident(name, false) if name == kw::True || name == kw::False => + token::Ident(name, false) if name.is_bool_lit() => token::Lit::new(token::Bool, name, None), token::Literal(lit) => lit, diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 3eb4d45045a..d4b13cc2e01 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -423,7 +423,7 @@ impl<'a> Parser<'a> { // FIXME(const_generics): to distinguish between idents for types and consts, // we should introduce a GenericArg::Ident in the AST and distinguish when // lowering to the HIR. For now, idents for const args are not permitted. - if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) { + if self.token.is_bool_lit() { self.parse_literal_maybe_minus()? } else { return Err( diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index dfea34c331a..fe3b51aa246 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -417,10 +417,8 @@ impl Token { /// for example a '-42', or one of the boolean idents). crate fn can_begin_literal_or_bool(&self) -> bool { match self.kind { - Literal(..) => true, - BinOp(Minus) => true, - Ident(name, false) if name == kw::True => true, - Ident(name, false) if name == kw::False => true, + Literal(..) | BinOp(Minus) => true, + Ident(name, false) if name.is_bool_lit() => true, Interpolated(ref nt) => match **nt { NtLiteral(..) => true, _ => false, @@ -537,6 +535,11 @@ impl Token { self.is_non_raw_ident_where(ast::Ident::is_reserved) } + /// Returns `true` if the token is the identifier `true` or `false`. + crate fn is_bool_lit(&self) -> bool { + self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) + } + /// Returns `true` if the token is a non-raw identifier for which `pred` holds. fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool { match self.ident() { diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 0b8f16bbc3b..856857f74e3 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -1063,6 +1063,11 @@ impl Symbol { self == kw::DollarCrate } + /// Returns `true` if the symbol is `true` or `false`. + pub fn is_bool_lit(self) -> bool { + self == kw::True || self == kw::False + } + /// This symbol can be a raw identifier. pub fn can_be_raw(self) -> bool { self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword() -- cgit 1.4.1-3-g733a5 From f908aa9e8000dd7fd2c3de54fe1d914fddf4fe92 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 27 Aug 2019 13:04:48 +0200 Subject: recover on 'mut ' and improve recovery for keywords. --- src/libsyntax/parse/parser/pat.rs | 136 ++++++++++++++++----- .../extern/keyword-extern-as-identifier-pat.rs | 2 +- .../extern/keyword-extern-as-identifier-pat.stderr | 8 +- src/test/ui/parser/issue-32501.rs | 3 +- src/test/ui/parser/issue-32501.stderr | 6 +- src/test/ui/parser/keyword-abstract.rs | 2 +- src/test/ui/parser/keyword-abstract.stderr | 8 +- src/test/ui/parser/keyword-as-as-identifier.rs | 2 +- src/test/ui/parser/keyword-as-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-break-as-identifier.rs | 2 +- .../ui/parser/keyword-break-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-const-as-identifier.rs | 2 +- .../ui/parser/keyword-const-as-identifier.stderr | 8 +- .../ui/parser/keyword-continue-as-identifier.rs | 2 +- .../parser/keyword-continue-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-else-as-identifier.rs | 2 +- .../ui/parser/keyword-else-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-enum-as-identifier.rs | 2 +- .../ui/parser/keyword-enum-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-final.rs | 2 +- src/test/ui/parser/keyword-final.stderr | 8 +- src/test/ui/parser/keyword-fn-as-identifier.rs | 2 +- src/test/ui/parser/keyword-fn-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-for-as-identifier.rs | 2 +- .../ui/parser/keyword-for-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-if-as-identifier.rs | 2 +- src/test/ui/parser/keyword-if-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-impl-as-identifier.rs | 2 +- .../ui/parser/keyword-impl-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-let-as-identifier.rs | 2 +- .../ui/parser/keyword-let-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-loop-as-identifier.rs | 2 +- .../ui/parser/keyword-loop-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-match-as-identifier.rs | 2 +- .../ui/parser/keyword-match-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-mod-as-identifier.rs | 2 +- .../ui/parser/keyword-mod-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-move-as-identifier.rs | 2 +- .../ui/parser/keyword-move-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-override.rs | 2 +- src/test/ui/parser/keyword-override.stderr | 8 +- src/test/ui/parser/keyword-pub-as-identifier.rs | 2 +- .../ui/parser/keyword-pub-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-return-as-identifier.rs | 2 +- .../ui/parser/keyword-return-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-static-as-identifier.rs | 2 +- .../ui/parser/keyword-static-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-struct-as-identifier.rs | 2 +- .../ui/parser/keyword-struct-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-trait-as-identifier.rs | 2 +- .../ui/parser/keyword-trait-as-identifier.stderr | 8 +- .../keyword-try-as-identifier-edition2018.rs | 2 +- .../keyword-try-as-identifier-edition2018.stderr | 8 +- src/test/ui/parser/keyword-type-as-identifier.rs | 2 +- .../ui/parser/keyword-type-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-typeof.rs | 2 +- src/test/ui/parser/keyword-typeof.stderr | 8 +- src/test/ui/parser/keyword-unsafe-as-identifier.rs | 2 +- .../ui/parser/keyword-unsafe-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-use-as-identifier.rs | 2 +- .../ui/parser/keyword-use-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-where-as-identifier.rs | 2 +- .../ui/parser/keyword-where-as-identifier.stderr | 8 +- src/test/ui/parser/keyword-while-as-identifier.rs | 2 +- .../ui/parser/keyword-while-as-identifier.stderr | 8 +- src/test/ui/parser/mut-patterns.rs | 30 ++++- src/test/ui/parser/mut-patterns.stderr | 68 ++++++++++- src/test/ui/reserved/reserved-become.rs | 2 +- src/test/ui/reserved/reserved-become.stderr | 8 +- src/test/ui/self/self_type_keyword.rs | 3 +- src/test/ui/self/self_type_keyword.stderr | 30 +++-- 71 files changed, 449 insertions(+), 147 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 78c9a289b37..7b228a700a7 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -4,6 +4,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::ptr::P; use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac}; use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind}; +use crate::mut_visit::{noop_visit_pat, MutVisitor}; use crate::parse::token::{self}; use crate::print::pprust; use crate::source_map::{respan, Span, Spanned}; @@ -273,7 +274,7 @@ impl<'a> Parser<'a> { // Parse _ PatKind::Wild } else if self.eat_keyword(kw::Mut) { - self.recover_pat_ident_mut_first()? + self.parse_pat_ident_mut()? } else if self.eat_keyword(kw::Ref) { // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); @@ -281,13 +282,12 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Box) { // Parse `box pat` PatKind::Box(self.parse_pat_with_range_pat(false, None)?) - } else if self.token.is_ident() && !self.token.is_reserved_ident() && - self.parse_as_ident() { + } else if self.can_be_ident_pat() { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. self.parse_pat_ident(BindingMode::ByValue(Mutability::Immutable))? - } else if self.token.is_path_start() { + } else if self.is_start_of_pat_with_path() { // Parse pattern starting with a path let (qself, path) = if self.eat_lt() { // Parse a qualified path @@ -384,24 +384,85 @@ impl<'a> Parser<'a> { }) } + fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> { + let mut_span = self.prev_span; + + if self.eat_keyword(kw::Ref) { + return self.recover_mut_ref_ident(mut_span) + } + + self.recover_additional_muts(); + + let mut pat = self.parse_pat(Some("identifier"))?; + + // Add `mut` to any binding in the parsed pattern. + struct AddMut; + impl MutVisitor for AddMut { + fn visit_pat(&mut self, pat: &mut P) { + if let PatKind::Ident(BindingMode::ByValue(ref mut m), ..) = pat.node { + *m = Mutability::Mutable; + } + noop_visit_pat(pat, self); + } + } + AddMut.visit_pat(&mut pat); + + // Unwrap; If we don't have `mut $ident`, error. + let pat = pat.into_inner(); + match &pat.node { + PatKind::Ident(..) => {} + _ => self.ban_mut_general_pat(mut_span, &pat), + } + + Ok(pat.node) + } + /// Recover on `mut ref? ident @ pat` and suggest /// that the order of `mut` and `ref` is incorrect. - fn recover_pat_ident_mut_first(&mut self) -> PResult<'a, PatKind> { - let mutref_span = self.prev_span.to(self.token.span); - let binding_mode = if self.eat_keyword(kw::Ref) { - self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") - .span_suggestion( - mutref_span, - "try switching the order", - "ref mut".into(), - Applicability::MachineApplicable - ) - .emit(); - BindingMode::ByRef(Mutability::Mutable) - } else { - BindingMode::ByValue(Mutability::Mutable) - }; - self.parse_pat_ident(binding_mode) + fn recover_mut_ref_ident(&mut self, lo: Span) -> PResult<'a, PatKind> { + let mutref_span = lo.to(self.prev_span); + self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") + .span_suggestion( + mutref_span, + "try switching the order", + "ref mut".into(), + Applicability::MachineApplicable + ) + .emit(); + + self.parse_pat_ident(BindingMode::ByRef(Mutability::Mutable)) + } + + /// Error on `mut $pat` where `$pat` is not an ident. + fn ban_mut_general_pat(&self, lo: Span, pat: &Pat) { + let span = lo.to(pat.span); + self.struct_span_err(span, "`mut` must be attached to each individual binding") + .span_suggestion( + span, + "add `mut` to each binding", + pprust::pat_to_string(&pat), + Applicability::MachineApplicable, + ) + .emit(); + } + + /// Eat any extraneous `mut`s and error + recover if we ate any. + fn recover_additional_muts(&mut self) { + let lo = self.token.span; + while self.eat_keyword(kw::Mut) {} + if lo == self.token.span { + return; + } + + let span = lo.to(self.prev_span); + self.struct_span_err(span, "`mut` on a binding may not be repeated") + .span_suggestion( + span, + "remove the additional `mut`s", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); } /// Parse macro invocation @@ -479,17 +540,6 @@ impl<'a> Parser<'a> { Err(err) } - // Helper function to decide whether to parse as ident binding - // or to try to do something more complex like range patterns. - fn parse_as_ident(&mut self) -> bool { - self.look_ahead(1, |t| match t.kind { - token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | - token::DotDotDot | token::DotDotEq | token::DotDot | - token::ModSep | token::Not => false, - _ => true, - }) - } - /// Is the current token suitable as the start of a range patterns end? fn is_pat_range_end_start(&self) -> bool { self.token.is_path_start() // e.g. `MY_CONST`; @@ -563,6 +613,30 @@ impl<'a> Parser<'a> { } } + /// Is this the start of a pattern beginning with a path? + fn is_start_of_pat_with_path(&mut self) -> bool { + self.check_path() + // Just for recovery (see `can_be_ident`). + || self.token.is_ident() && !self.token.is_bool_lit() && !self.token.is_keyword(kw::In) + } + + /// Would `parse_pat_ident` be appropriate here? + fn can_be_ident_pat(&mut self) -> bool { + self.check_ident() + && !self.token.is_bool_lit() // Avoid `true` or `false` as a binding as it is a literal. + && !self.token.is_path_segment_keyword() // Avoid e.g. `Self` as it is a path. + // Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`. + && !self.token.is_keyword(kw::In) + && self.look_ahead(1, |t| match t.kind { // Try to do something more complex? + token::OpenDelim(token::Paren) // A tuple struct pattern. + | token::OpenDelim(token::Brace) // A struct pattern. + | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern. + | token::ModSep // A tuple / struct variant pattern. + | token::Not => false, // A macro expanding to a pattern. + _ => true, + }) + } + /// Parses `ident` or `ident @ pat`. /// Used by the copy foo and ref foo patterns to give a good /// error message when parsing mistakes like `ref foo(a, b)`. diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs index f9b6bad7c25..8a420f7203c 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs @@ -1,3 +1,3 @@ fn main() { - let extern = 0; //~ ERROR expected pattern, found keyword `extern` + let extern = 0; //~ ERROR expected identifier, found keyword `extern` } diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr index d7b9ad2abe9..73ac113f1b1 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `extern` +error: expected identifier, found keyword `extern` --> $DIR/keyword-extern-as-identifier-pat.rs:2:9 | LL | let extern = 0; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#extern = 0; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/issue-32501.rs b/src/test/ui/parser/issue-32501.rs index 9c01a5c6d20..695baf81872 100644 --- a/src/test/ui/parser/issue-32501.rs +++ b/src/test/ui/parser/issue-32501.rs @@ -4,5 +4,6 @@ fn main() { let _ = 0; let mut b = 0; let mut _b = 0; - let mut _ = 0; //~ ERROR expected identifier, found reserved identifier `_` + let mut _ = 0; + //~^ ERROR `mut` must be attached to each individual binding } diff --git a/src/test/ui/parser/issue-32501.stderr b/src/test/ui/parser/issue-32501.stderr index 97efb895935..f5d3300cf9c 100644 --- a/src/test/ui/parser/issue-32501.stderr +++ b/src/test/ui/parser/issue-32501.stderr @@ -1,8 +1,8 @@ -error: expected identifier, found reserved identifier `_` - --> $DIR/issue-32501.rs:7:13 +error: `mut` must be attached to each individual binding + --> $DIR/issue-32501.rs:7:9 | LL | let mut _ = 0; - | ^ expected identifier, found reserved identifier + | ^^^^^ help: add `mut` to each binding: `_` error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-abstract.rs b/src/test/ui/parser/keyword-abstract.rs index 890802ac134..570206575ab 100644 --- a/src/test/ui/parser/keyword-abstract.rs +++ b/src/test/ui/parser/keyword-abstract.rs @@ -1,3 +1,3 @@ fn main() { - let abstract = (); //~ ERROR expected pattern, found reserved keyword `abstract` + let abstract = (); //~ ERROR expected identifier, found reserved keyword `abstract` } diff --git a/src/test/ui/parser/keyword-abstract.stderr b/src/test/ui/parser/keyword-abstract.stderr index 2c79598a81b..eb2c810099e 100644 --- a/src/test/ui/parser/keyword-abstract.stderr +++ b/src/test/ui/parser/keyword-abstract.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `abstract` +error: expected identifier, found reserved keyword `abstract` --> $DIR/keyword-abstract.rs:2:9 | LL | let abstract = (); - | ^^^^^^^^ expected pattern + | ^^^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#abstract = (); + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-as-as-identifier.rs b/src/test/ui/parser/keyword-as-as-identifier.rs index 23ff259db30..cd47c8a3907 100644 --- a/src/test/ui/parser/keyword-as-as-identifier.rs +++ b/src/test/ui/parser/keyword-as-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py as' fn main() { - let as = "foo"; //~ error: expected pattern, found keyword `as` + let as = "foo"; //~ error: expected identifier, found keyword `as` } diff --git a/src/test/ui/parser/keyword-as-as-identifier.stderr b/src/test/ui/parser/keyword-as-as-identifier.stderr index ef466488ad0..5648652be9b 100644 --- a/src/test/ui/parser/keyword-as-as-identifier.stderr +++ b/src/test/ui/parser/keyword-as-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `as` +error: expected identifier, found keyword `as` --> $DIR/keyword-as-as-identifier.rs:4:9 | LL | let as = "foo"; - | ^^ expected pattern + | ^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#as = "foo"; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-break-as-identifier.rs b/src/test/ui/parser/keyword-break-as-identifier.rs index 5ee111d38c9..04b25a7aaf6 100644 --- a/src/test/ui/parser/keyword-break-as-identifier.rs +++ b/src/test/ui/parser/keyword-break-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py break' fn main() { - let break = "foo"; //~ error: expected pattern, found keyword `break` + let break = "foo"; //~ error: expected identifier, found keyword `break` } diff --git a/src/test/ui/parser/keyword-break-as-identifier.stderr b/src/test/ui/parser/keyword-break-as-identifier.stderr index 690bd84221a..820193db70b 100644 --- a/src/test/ui/parser/keyword-break-as-identifier.stderr +++ b/src/test/ui/parser/keyword-break-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `break` +error: expected identifier, found keyword `break` --> $DIR/keyword-break-as-identifier.rs:4:9 | LL | let break = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#break = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-const-as-identifier.rs b/src/test/ui/parser/keyword-const-as-identifier.rs index 48fc142cf64..6a2d926bf57 100644 --- a/src/test/ui/parser/keyword-const-as-identifier.rs +++ b/src/test/ui/parser/keyword-const-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py const' fn main() { - let const = "foo"; //~ error: expected pattern, found keyword `const` + let const = "foo"; //~ error: expected identifier, found keyword `const` } diff --git a/src/test/ui/parser/keyword-const-as-identifier.stderr b/src/test/ui/parser/keyword-const-as-identifier.stderr index 6da47f88d04..95b536c99c7 100644 --- a/src/test/ui/parser/keyword-const-as-identifier.stderr +++ b/src/test/ui/parser/keyword-const-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `const` +error: expected identifier, found keyword `const` --> $DIR/keyword-const-as-identifier.rs:4:9 | LL | let const = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#const = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-continue-as-identifier.rs b/src/test/ui/parser/keyword-continue-as-identifier.rs index 06315a48349..cfdd62a2d1b 100644 --- a/src/test/ui/parser/keyword-continue-as-identifier.rs +++ b/src/test/ui/parser/keyword-continue-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py continue' fn main() { - let continue = "foo"; //~ error: expected pattern, found keyword `continue` + let continue = "foo"; //~ error: expected identifier, found keyword `continue` } diff --git a/src/test/ui/parser/keyword-continue-as-identifier.stderr b/src/test/ui/parser/keyword-continue-as-identifier.stderr index 4b0a659f9ad..6b24422a555 100644 --- a/src/test/ui/parser/keyword-continue-as-identifier.stderr +++ b/src/test/ui/parser/keyword-continue-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `continue` +error: expected identifier, found keyword `continue` --> $DIR/keyword-continue-as-identifier.rs:4:9 | LL | let continue = "foo"; - | ^^^^^^^^ expected pattern + | ^^^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#continue = "foo"; + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-else-as-identifier.rs b/src/test/ui/parser/keyword-else-as-identifier.rs index 0c69105cf94..f12dac3ff75 100644 --- a/src/test/ui/parser/keyword-else-as-identifier.rs +++ b/src/test/ui/parser/keyword-else-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py else' fn main() { - let else = "foo"; //~ error: expected pattern, found keyword `else` + let else = "foo"; //~ error: expected identifier, found keyword `else` } diff --git a/src/test/ui/parser/keyword-else-as-identifier.stderr b/src/test/ui/parser/keyword-else-as-identifier.stderr index bec7b7ba01e..f28635cd08c 100644 --- a/src/test/ui/parser/keyword-else-as-identifier.stderr +++ b/src/test/ui/parser/keyword-else-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `else` +error: expected identifier, found keyword `else` --> $DIR/keyword-else-as-identifier.rs:4:9 | LL | let else = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#else = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-enum-as-identifier.rs b/src/test/ui/parser/keyword-enum-as-identifier.rs index d1675800a27..fe66230d028 100644 --- a/src/test/ui/parser/keyword-enum-as-identifier.rs +++ b/src/test/ui/parser/keyword-enum-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py enum' fn main() { - let enum = "foo"; //~ error: expected pattern, found keyword `enum` + let enum = "foo"; //~ error: expected identifier, found keyword `enum` } diff --git a/src/test/ui/parser/keyword-enum-as-identifier.stderr b/src/test/ui/parser/keyword-enum-as-identifier.stderr index 51a834f797c..fc54dce1b68 100644 --- a/src/test/ui/parser/keyword-enum-as-identifier.stderr +++ b/src/test/ui/parser/keyword-enum-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `enum` +error: expected identifier, found keyword `enum` --> $DIR/keyword-enum-as-identifier.rs:4:9 | LL | let enum = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#enum = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-final.rs b/src/test/ui/parser/keyword-final.rs index e1cecd0e8e0..a79a11032a0 100644 --- a/src/test/ui/parser/keyword-final.rs +++ b/src/test/ui/parser/keyword-final.rs @@ -1,3 +1,3 @@ fn main() { - let final = (); //~ ERROR expected pattern, found reserved keyword `final` + let final = (); //~ ERROR expected identifier, found reserved keyword `final` } diff --git a/src/test/ui/parser/keyword-final.stderr b/src/test/ui/parser/keyword-final.stderr index e8372643be6..291710d05cb 100644 --- a/src/test/ui/parser/keyword-final.stderr +++ b/src/test/ui/parser/keyword-final.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `final` +error: expected identifier, found reserved keyword `final` --> $DIR/keyword-final.rs:2:9 | LL | let final = (); - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#final = (); + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-fn-as-identifier.rs b/src/test/ui/parser/keyword-fn-as-identifier.rs index bca2d5996a5..f30e115f794 100644 --- a/src/test/ui/parser/keyword-fn-as-identifier.rs +++ b/src/test/ui/parser/keyword-fn-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py fn' fn main() { - let fn = "foo"; //~ error: expected pattern, found keyword `fn` + let fn = "foo"; //~ error: expected identifier, found keyword `fn` } diff --git a/src/test/ui/parser/keyword-fn-as-identifier.stderr b/src/test/ui/parser/keyword-fn-as-identifier.stderr index a071a40a70e..692f195b288 100644 --- a/src/test/ui/parser/keyword-fn-as-identifier.stderr +++ b/src/test/ui/parser/keyword-fn-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `fn` +error: expected identifier, found keyword `fn` --> $DIR/keyword-fn-as-identifier.rs:4:9 | LL | let fn = "foo"; - | ^^ expected pattern + | ^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#fn = "foo"; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-for-as-identifier.rs b/src/test/ui/parser/keyword-for-as-identifier.rs index ce49fd90d91..9e8a2ad5342 100644 --- a/src/test/ui/parser/keyword-for-as-identifier.rs +++ b/src/test/ui/parser/keyword-for-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py for' fn main() { - let for = "foo"; //~ error: expected pattern, found keyword `for` + let for = "foo"; //~ error: expected identifier, found keyword `for` } diff --git a/src/test/ui/parser/keyword-for-as-identifier.stderr b/src/test/ui/parser/keyword-for-as-identifier.stderr index 090046cebdc..bcaf421286e 100644 --- a/src/test/ui/parser/keyword-for-as-identifier.stderr +++ b/src/test/ui/parser/keyword-for-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `for` +error: expected identifier, found keyword `for` --> $DIR/keyword-for-as-identifier.rs:4:9 | LL | let for = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#for = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-if-as-identifier.rs b/src/test/ui/parser/keyword-if-as-identifier.rs index a1302970689..0bd5756afce 100644 --- a/src/test/ui/parser/keyword-if-as-identifier.rs +++ b/src/test/ui/parser/keyword-if-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py if' fn main() { - let if = "foo"; //~ error: expected pattern, found keyword `if` + let if = "foo"; //~ error: expected identifier, found keyword `if` } diff --git a/src/test/ui/parser/keyword-if-as-identifier.stderr b/src/test/ui/parser/keyword-if-as-identifier.stderr index 98bfdb46e97..43fbcd7148a 100644 --- a/src/test/ui/parser/keyword-if-as-identifier.stderr +++ b/src/test/ui/parser/keyword-if-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `if` +error: expected identifier, found keyword `if` --> $DIR/keyword-if-as-identifier.rs:4:9 | LL | let if = "foo"; - | ^^ expected pattern + | ^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#if = "foo"; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-impl-as-identifier.rs b/src/test/ui/parser/keyword-impl-as-identifier.rs index 95a34483ad2..df529bae072 100644 --- a/src/test/ui/parser/keyword-impl-as-identifier.rs +++ b/src/test/ui/parser/keyword-impl-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py impl' fn main() { - let impl = "foo"; //~ error: expected pattern, found keyword `impl` + let impl = "foo"; //~ error: expected identifier, found keyword `impl` } diff --git a/src/test/ui/parser/keyword-impl-as-identifier.stderr b/src/test/ui/parser/keyword-impl-as-identifier.stderr index 2672959b7c6..01886eb45cb 100644 --- a/src/test/ui/parser/keyword-impl-as-identifier.stderr +++ b/src/test/ui/parser/keyword-impl-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `impl` +error: expected identifier, found keyword `impl` --> $DIR/keyword-impl-as-identifier.rs:4:9 | LL | let impl = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#impl = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-let-as-identifier.rs b/src/test/ui/parser/keyword-let-as-identifier.rs index 07c0ddf8ce5..9b1183501b2 100644 --- a/src/test/ui/parser/keyword-let-as-identifier.rs +++ b/src/test/ui/parser/keyword-let-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py let' fn main() { - let let = "foo"; //~ error: expected pattern, found keyword `let` + let let = "foo"; //~ error: expected identifier, found keyword `let` } diff --git a/src/test/ui/parser/keyword-let-as-identifier.stderr b/src/test/ui/parser/keyword-let-as-identifier.stderr index 99dbc0530f3..f6c39077be2 100644 --- a/src/test/ui/parser/keyword-let-as-identifier.stderr +++ b/src/test/ui/parser/keyword-let-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `let` +error: expected identifier, found keyword `let` --> $DIR/keyword-let-as-identifier.rs:4:9 | LL | let let = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#let = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-loop-as-identifier.rs b/src/test/ui/parser/keyword-loop-as-identifier.rs index 8643ffe4345..46914a19be2 100644 --- a/src/test/ui/parser/keyword-loop-as-identifier.rs +++ b/src/test/ui/parser/keyword-loop-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py loop' fn main() { - let loop = "foo"; //~ error: expected pattern, found keyword `loop` + let loop = "foo"; //~ error: expected identifier, found keyword `loop` } diff --git a/src/test/ui/parser/keyword-loop-as-identifier.stderr b/src/test/ui/parser/keyword-loop-as-identifier.stderr index 783507eb35c..f0c282faa29 100644 --- a/src/test/ui/parser/keyword-loop-as-identifier.stderr +++ b/src/test/ui/parser/keyword-loop-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `loop` +error: expected identifier, found keyword `loop` --> $DIR/keyword-loop-as-identifier.rs:4:9 | LL | let loop = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#loop = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-match-as-identifier.rs b/src/test/ui/parser/keyword-match-as-identifier.rs index 8ef6b6810a5..d3cecb991b8 100644 --- a/src/test/ui/parser/keyword-match-as-identifier.rs +++ b/src/test/ui/parser/keyword-match-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py match' fn main() { - let match = "foo"; //~ error: expected pattern, found keyword `match` + let match = "foo"; //~ error: expected identifier, found keyword `match` } diff --git a/src/test/ui/parser/keyword-match-as-identifier.stderr b/src/test/ui/parser/keyword-match-as-identifier.stderr index e56a115c916..f1f4397d194 100644 --- a/src/test/ui/parser/keyword-match-as-identifier.stderr +++ b/src/test/ui/parser/keyword-match-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `match` +error: expected identifier, found keyword `match` --> $DIR/keyword-match-as-identifier.rs:4:9 | LL | let match = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#match = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-mod-as-identifier.rs b/src/test/ui/parser/keyword-mod-as-identifier.rs index 96bcdccf0a0..b9c7b6c78ed 100644 --- a/src/test/ui/parser/keyword-mod-as-identifier.rs +++ b/src/test/ui/parser/keyword-mod-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py mod' fn main() { - let mod = "foo"; //~ error: expected pattern, found keyword `mod` + let mod = "foo"; //~ error: expected identifier, found keyword `mod` } diff --git a/src/test/ui/parser/keyword-mod-as-identifier.stderr b/src/test/ui/parser/keyword-mod-as-identifier.stderr index a8be2ceb037..65ae3baa8c2 100644 --- a/src/test/ui/parser/keyword-mod-as-identifier.stderr +++ b/src/test/ui/parser/keyword-mod-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `mod` +error: expected identifier, found keyword `mod` --> $DIR/keyword-mod-as-identifier.rs:4:9 | LL | let mod = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#mod = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-move-as-identifier.rs b/src/test/ui/parser/keyword-move-as-identifier.rs index 2193af530bd..65be02e3c70 100644 --- a/src/test/ui/parser/keyword-move-as-identifier.rs +++ b/src/test/ui/parser/keyword-move-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py move' fn main() { - let move = "foo"; //~ error: expected pattern, found keyword `move` + let move = "foo"; //~ error: expected identifier, found keyword `move` } diff --git a/src/test/ui/parser/keyword-move-as-identifier.stderr b/src/test/ui/parser/keyword-move-as-identifier.stderr index e0687e27eb5..216f7c931ee 100644 --- a/src/test/ui/parser/keyword-move-as-identifier.stderr +++ b/src/test/ui/parser/keyword-move-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `move` +error: expected identifier, found keyword `move` --> $DIR/keyword-move-as-identifier.rs:4:9 | LL | let move = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#move = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-override.rs b/src/test/ui/parser/keyword-override.rs index 948a20095f1..009bebd7ddb 100644 --- a/src/test/ui/parser/keyword-override.rs +++ b/src/test/ui/parser/keyword-override.rs @@ -1,3 +1,3 @@ fn main() { - let override = (); //~ ERROR expected pattern, found reserved keyword `override` + let override = (); //~ ERROR expected identifier, found reserved keyword `override` } diff --git a/src/test/ui/parser/keyword-override.stderr b/src/test/ui/parser/keyword-override.stderr index 1bfc6c9b385..3183fa510c2 100644 --- a/src/test/ui/parser/keyword-override.stderr +++ b/src/test/ui/parser/keyword-override.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `override` +error: expected identifier, found reserved keyword `override` --> $DIR/keyword-override.rs:2:9 | LL | let override = (); - | ^^^^^^^^ expected pattern + | ^^^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#override = (); + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-pub-as-identifier.rs b/src/test/ui/parser/keyword-pub-as-identifier.rs index 2ed8cc6b268..2b2bb14118d 100644 --- a/src/test/ui/parser/keyword-pub-as-identifier.rs +++ b/src/test/ui/parser/keyword-pub-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py pub' fn main() { - let pub = "foo"; //~ error: expected pattern, found keyword `pub` + let pub = "foo"; //~ error: expected identifier, found keyword `pub` } diff --git a/src/test/ui/parser/keyword-pub-as-identifier.stderr b/src/test/ui/parser/keyword-pub-as-identifier.stderr index 526ddcd6ee0..f81078b12bd 100644 --- a/src/test/ui/parser/keyword-pub-as-identifier.stderr +++ b/src/test/ui/parser/keyword-pub-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `pub` +error: expected identifier, found keyword `pub` --> $DIR/keyword-pub-as-identifier.rs:4:9 | LL | let pub = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#pub = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-return-as-identifier.rs b/src/test/ui/parser/keyword-return-as-identifier.rs index 920931b00f9..e1a2db5e4d8 100644 --- a/src/test/ui/parser/keyword-return-as-identifier.rs +++ b/src/test/ui/parser/keyword-return-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py return' fn main() { - let return = "foo"; //~ error: expected pattern, found keyword `return` + let return = "foo"; //~ error: expected identifier, found keyword `return` } diff --git a/src/test/ui/parser/keyword-return-as-identifier.stderr b/src/test/ui/parser/keyword-return-as-identifier.stderr index c0156a63fa9..8cc4d12fbbb 100644 --- a/src/test/ui/parser/keyword-return-as-identifier.stderr +++ b/src/test/ui/parser/keyword-return-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `return` +error: expected identifier, found keyword `return` --> $DIR/keyword-return-as-identifier.rs:4:9 | LL | let return = "foo"; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#return = "foo"; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-static-as-identifier.rs b/src/test/ui/parser/keyword-static-as-identifier.rs index 3ccbfccfc93..423b9854b8a 100644 --- a/src/test/ui/parser/keyword-static-as-identifier.rs +++ b/src/test/ui/parser/keyword-static-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py static' fn main() { - let static = "foo"; //~ error: expected pattern, found keyword `static` + let static = "foo"; //~ error: expected identifier, found keyword `static` } diff --git a/src/test/ui/parser/keyword-static-as-identifier.stderr b/src/test/ui/parser/keyword-static-as-identifier.stderr index 00a65977732..7d22bc97d66 100644 --- a/src/test/ui/parser/keyword-static-as-identifier.stderr +++ b/src/test/ui/parser/keyword-static-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `static` +error: expected identifier, found keyword `static` --> $DIR/keyword-static-as-identifier.rs:4:9 | LL | let static = "foo"; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#static = "foo"; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-struct-as-identifier.rs b/src/test/ui/parser/keyword-struct-as-identifier.rs index 69d8f190655..18cfe11592a 100644 --- a/src/test/ui/parser/keyword-struct-as-identifier.rs +++ b/src/test/ui/parser/keyword-struct-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py struct' fn main() { - let struct = "foo"; //~ error: expected pattern, found keyword `struct` + let struct = "foo"; //~ error: expected identifier, found keyword `struct` } diff --git a/src/test/ui/parser/keyword-struct-as-identifier.stderr b/src/test/ui/parser/keyword-struct-as-identifier.stderr index b2d6639e72e..b109fa6247d 100644 --- a/src/test/ui/parser/keyword-struct-as-identifier.stderr +++ b/src/test/ui/parser/keyword-struct-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `struct` +error: expected identifier, found keyword `struct` --> $DIR/keyword-struct-as-identifier.rs:4:9 | LL | let struct = "foo"; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#struct = "foo"; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-trait-as-identifier.rs b/src/test/ui/parser/keyword-trait-as-identifier.rs index f62858442d2..67f81167dbd 100644 --- a/src/test/ui/parser/keyword-trait-as-identifier.rs +++ b/src/test/ui/parser/keyword-trait-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py trait' fn main() { - let trait = "foo"; //~ error: expected pattern, found keyword `trait` + let trait = "foo"; //~ error: expected identifier, found keyword `trait` } diff --git a/src/test/ui/parser/keyword-trait-as-identifier.stderr b/src/test/ui/parser/keyword-trait-as-identifier.stderr index b31c0df28c0..ccc675cdb3a 100644 --- a/src/test/ui/parser/keyword-trait-as-identifier.stderr +++ b/src/test/ui/parser/keyword-trait-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `trait` +error: expected identifier, found keyword `trait` --> $DIR/keyword-trait-as-identifier.rs:4:9 | LL | let trait = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#trait = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs b/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs index 13a938b2e09..4fa37bdb057 100644 --- a/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs +++ b/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs @@ -1,5 +1,5 @@ // compile-flags: --edition 2018 fn main() { - let try = "foo"; //~ error: expected pattern, found reserved keyword `try` + let try = "foo"; //~ error: expected identifier, found reserved keyword `try` } diff --git a/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr b/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr index c342e3a76fb..f71b889a30d 100644 --- a/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr +++ b/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `try` +error: expected identifier, found reserved keyword `try` --> $DIR/keyword-try-as-identifier-edition2018.rs:4:9 | LL | let try = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#try = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-type-as-identifier.rs b/src/test/ui/parser/keyword-type-as-identifier.rs index 992547e6f59..04adddf72c6 100644 --- a/src/test/ui/parser/keyword-type-as-identifier.rs +++ b/src/test/ui/parser/keyword-type-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py type' fn main() { - let type = "foo"; //~ error: expected pattern, found keyword `type` + let type = "foo"; //~ error: expected identifier, found keyword `type` } diff --git a/src/test/ui/parser/keyword-type-as-identifier.stderr b/src/test/ui/parser/keyword-type-as-identifier.stderr index b749c708d44..88099d949a8 100644 --- a/src/test/ui/parser/keyword-type-as-identifier.stderr +++ b/src/test/ui/parser/keyword-type-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `type` +error: expected identifier, found keyword `type` --> $DIR/keyword-type-as-identifier.rs:4:9 | LL | let type = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#type = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-typeof.rs b/src/test/ui/parser/keyword-typeof.rs index 4ef102646ef..29dc77d276c 100644 --- a/src/test/ui/parser/keyword-typeof.rs +++ b/src/test/ui/parser/keyword-typeof.rs @@ -1,3 +1,3 @@ fn main() { - let typeof = (); //~ ERROR expected pattern, found reserved keyword `typeof` + let typeof = (); //~ ERROR expected identifier, found reserved keyword `typeof` } diff --git a/src/test/ui/parser/keyword-typeof.stderr b/src/test/ui/parser/keyword-typeof.stderr index e7b18023e61..4a1b63d5c93 100644 --- a/src/test/ui/parser/keyword-typeof.stderr +++ b/src/test/ui/parser/keyword-typeof.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `typeof` +error: expected identifier, found reserved keyword `typeof` --> $DIR/keyword-typeof.rs:2:9 | LL | let typeof = (); - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#typeof = (); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-unsafe-as-identifier.rs b/src/test/ui/parser/keyword-unsafe-as-identifier.rs index adb20ebe48c..0ff6d188c64 100644 --- a/src/test/ui/parser/keyword-unsafe-as-identifier.rs +++ b/src/test/ui/parser/keyword-unsafe-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py unsafe' fn main() { - let unsafe = "foo"; //~ error: expected pattern, found keyword `unsafe` + let unsafe = "foo"; //~ error: expected identifier, found keyword `unsafe` } diff --git a/src/test/ui/parser/keyword-unsafe-as-identifier.stderr b/src/test/ui/parser/keyword-unsafe-as-identifier.stderr index 67935ce43ba..205bb81df40 100644 --- a/src/test/ui/parser/keyword-unsafe-as-identifier.stderr +++ b/src/test/ui/parser/keyword-unsafe-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `unsafe` +error: expected identifier, found keyword `unsafe` --> $DIR/keyword-unsafe-as-identifier.rs:4:9 | LL | let unsafe = "foo"; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#unsafe = "foo"; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-use-as-identifier.rs b/src/test/ui/parser/keyword-use-as-identifier.rs index 198444bafc5..821bedee088 100644 --- a/src/test/ui/parser/keyword-use-as-identifier.rs +++ b/src/test/ui/parser/keyword-use-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py use' fn main() { - let use = "foo"; //~ error: expected pattern, found keyword `use` + let use = "foo"; //~ error: expected identifier, found keyword `use` } diff --git a/src/test/ui/parser/keyword-use-as-identifier.stderr b/src/test/ui/parser/keyword-use-as-identifier.stderr index 2c69d0a8744..85a0492f573 100644 --- a/src/test/ui/parser/keyword-use-as-identifier.stderr +++ b/src/test/ui/parser/keyword-use-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `use` +error: expected identifier, found keyword `use` --> $DIR/keyword-use-as-identifier.rs:4:9 | LL | let use = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#use = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-where-as-identifier.rs b/src/test/ui/parser/keyword-where-as-identifier.rs index 5624a8fc460..56301bd20ad 100644 --- a/src/test/ui/parser/keyword-where-as-identifier.rs +++ b/src/test/ui/parser/keyword-where-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py where' fn main() { - let where = "foo"; //~ error: expected pattern, found keyword `where` + let where = "foo"; //~ error: expected identifier, found keyword `where` } diff --git a/src/test/ui/parser/keyword-where-as-identifier.stderr b/src/test/ui/parser/keyword-where-as-identifier.stderr index fc01183ca04..b8b85069076 100644 --- a/src/test/ui/parser/keyword-where-as-identifier.stderr +++ b/src/test/ui/parser/keyword-where-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `where` +error: expected identifier, found keyword `where` --> $DIR/keyword-where-as-identifier.rs:4:9 | LL | let where = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#where = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-while-as-identifier.rs b/src/test/ui/parser/keyword-while-as-identifier.rs index c0a539d3507..22026d15dcb 100644 --- a/src/test/ui/parser/keyword-while-as-identifier.rs +++ b/src/test/ui/parser/keyword-while-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py while' fn main() { - let while = "foo"; //~ error: expected pattern, found keyword `while` + let while = "foo"; //~ error: expected identifier, found keyword `while` } diff --git a/src/test/ui/parser/keyword-while-as-identifier.stderr b/src/test/ui/parser/keyword-while-as-identifier.stderr index f72ac877420..bb0c0ac668a 100644 --- a/src/test/ui/parser/keyword-while-as-identifier.stderr +++ b/src/test/ui/parser/keyword-while-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `while` +error: expected identifier, found keyword `while` --> $DIR/keyword-while-as-identifier.rs:4:9 | LL | let while = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#while = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index bffeb1e2e7c..87e127f9d36 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -1,7 +1,35 @@ // Can't put mut in non-ident pattern +// edition:2018 + +#![feature(box_patterns)] +#![allow(warnings)] + pub fn main() { + let mut mut x = 0; + //~^ ERROR `mut` on a binding may not be repeated + //~| remove the additional `mut`s + struct Foo { x: isize } let mut Foo { x: x } = Foo { x: 3 }; - //~^ ERROR: expected one of `:`, `;`, `=`, `@`, or `|`, found `{` + //~^ ERROR `mut` must be attached to each individual binding + //~| add `mut` to each binding + + let mut Foo { x } = Foo { x: 3 }; + //~^ ERROR `mut` must be attached to each individual binding + //~| add `mut` to each binding + + struct r#yield(u8, u8); + let mut mut yield(become, await) = r#yield(0, 0); + //~^ ERROR `mut` on a binding may not be repeated + //~| ERROR `mut` must be attached to each individual binding + //~| ERROR expected identifier, found reserved keyword `yield` + //~| ERROR expected identifier, found reserved keyword `become` + //~| ERROR expected identifier, found reserved keyword `await` + + struct W(T, U); + struct B { f: Box } + let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) + //~^ ERROR `mut` must be attached to each individual binding + = W(0, W(1, W(2, W(3, B { f: Box::new(4u8) })))); } diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index b39209afd42..a251e2908f0 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -1,8 +1,68 @@ -error: expected one of `:`, `;`, `=`, `@`, or `|`, found `{` - --> $DIR/mut-patterns.rs:5:17 +error: `mut` on a binding may not be repeated + --> $DIR/mut-patterns.rs:9:13 + | +LL | let mut mut x = 0; + | ^^^ help: remove the additional `mut`s + +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:14:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` here + | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` + +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:18:9 + | +LL | let mut Foo { x } = Foo { x: 3 }; + | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` + +error: `mut` on a binding may not be repeated + --> $DIR/mut-patterns.rs:23:13 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^ help: remove the additional `mut`s + +error: expected identifier, found reserved keyword `yield` + --> $DIR/mut-patterns.rs:23:17 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let mut mut r#yield(become, await) = r#yield(0, 0); + | ^^^^^^^ + +error: expected identifier, found reserved keyword `become` + --> $DIR/mut-patterns.rs:23:23 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let mut mut yield(r#become, await) = r#yield(0, 0); + | ^^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/mut-patterns.rs:23:31 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let mut mut yield(become, r#await) = r#yield(0, 0); + | ^^^^^^^ + +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:23:9 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)` + +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:32:9 + | +LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` -error: aborting due to previous error +error: aborting due to 9 previous errors diff --git a/src/test/ui/reserved/reserved-become.rs b/src/test/ui/reserved/reserved-become.rs index 2279a05e6b2..56645255ee5 100644 --- a/src/test/ui/reserved/reserved-become.rs +++ b/src/test/ui/reserved/reserved-become.rs @@ -1,4 +1,4 @@ fn main() { let become = 0; - //~^ ERROR expected pattern, found reserved keyword `become` + //~^ ERROR expected identifier, found reserved keyword `become` } diff --git a/src/test/ui/reserved/reserved-become.stderr b/src/test/ui/reserved/reserved-become.stderr index f9fe78e18b3..3ce9fb33c28 100644 --- a/src/test/ui/reserved/reserved-become.stderr +++ b/src/test/ui/reserved/reserved-become.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `become` +error: expected identifier, found reserved keyword `become` --> $DIR/reserved-become.rs:2:9 | LL | let become = 0; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#become = 0; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/self/self_type_keyword.rs b/src/test/ui/self/self_type_keyword.rs index 01b3309fcac..d479905932b 100644 --- a/src/test/ui/self/self_type_keyword.rs +++ b/src/test/ui/self/self_type_keyword.rs @@ -14,7 +14,8 @@ pub fn main() { ref Self => (), //~^ ERROR expected identifier, found keyword `Self` mut Self => (), - //~^ ERROR expected identifier, found keyword `Self` + //~^ ERROR `mut` must be attached to each individual binding + //~| ERROR cannot find unit struct/variant or constant `Self` ref mut Self => (), //~^ ERROR expected identifier, found keyword `Self` Self!() => (), diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index b63de98b8e7..fdae06ccdd9 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -10,38 +10,38 @@ error: expected identifier, found keyword `Self` LL | ref Self => (), | ^^^^ expected identifier, found keyword -error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:16:13 +error: `mut` must be attached to each individual binding + --> $DIR/self_type_keyword.rs:16:9 | LL | mut Self => (), - | ^^^^ expected identifier, found keyword + | ^^^^^^^^ help: add `mut` to each binding: `Self` error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:18:17 + --> $DIR/self_type_keyword.rs:19:17 | LL | ref mut Self => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:22:15 + --> $DIR/self_type_keyword.rs:23:15 | LL | Foo { Self } => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:28:26 + --> $DIR/self_type_keyword.rs:29:26 | LL | extern crate core as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:33:32 + --> $DIR/self_type_keyword.rs:34:32 | LL | use std::option::Option as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:38:11 + --> $DIR/self_type_keyword.rs:39:11 | LL | trait Self {} | ^^^^ expected identifier, found keyword @@ -53,11 +53,21 @@ LL | struct Bar<'Self>; | ^^^^^ error: cannot find macro `Self!` in this scope - --> $DIR/self_type_keyword.rs:20:9 + --> $DIR/self_type_keyword.rs:21:9 | LL | Self!() => (), | ^^^^ +error[E0531]: cannot find unit struct/variant or constant `Self` in this scope + --> $DIR/self_type_keyword.rs:16:13 + | +LL | mut Self => (), + | ^^^^ not found in this scope +help: possible candidate is found in another module, you can import it into scope + | +LL | use foo::Self; + | + error[E0392]: parameter `'Self` is never used --> $DIR/self_type_keyword.rs:6:12 | @@ -66,6 +76,6 @@ LL | struct Bar<'Self>; | = help: consider removing `'Self` or using a marker such as `std::marker::PhantomData` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0392`. -- cgit 1.4.1-3-g733a5 From e0ce9f8c0a97e5949c9cadd220279d6969289daa Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Tue, 27 Aug 2019 13:24:32 +0200 Subject: Cleanup: Consistently use `Param` instead of `Arg` #62426 --- src/librustc/hir/intravisit.rs | 14 ++-- src/librustc/hir/lowering.rs | 28 +++---- src/librustc/hir/lowering/item.rs | 80 +++++++++--------- src/librustc/hir/map/collector.rs | 10 +-- src/librustc/hir/map/mod.rs | 14 ++-- src/librustc/hir/mod.rs | 20 ++--- src/librustc/hir/print.rs | 16 ++-- src/librustc/ich/impls_hir.rs | 4 +- .../infer/error_reporting/need_type_info.rs | 6 +- .../nice_region_error/different_lifetimes.rs | 22 ++--- .../nice_region_error/named_anon_conflict.rs | 30 +++---- .../error_reporting/nice_region_error/util.rs | 44 +++++----- src/librustc/lint/context.rs | 16 ++-- src/librustc/lint/mod.rs | 10 +-- src/librustc/middle/expr_use_visitor.rs | 18 ++-- src/librustc/middle/liveness.rs | 22 ++--- src/librustc/middle/region.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc/traits/error_reporting.rs | 3 +- src/librustc_ast_borrowck/dataflow.rs | 4 +- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_metadata/decoder.rs | 10 +-- src/librustc_metadata/encoder.rs | 24 +++--- src/librustc_metadata/schema.rs | 2 +- src/librustc_mir/build/mod.rs | 4 +- src/librustc_mir/hair/pattern/check_match.rs | 6 +- src/librustc_passes/hir_stats.rs | 6 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/lib.rs | 4 +- src/librustc_typeck/check/demand.rs | 14 ++-- src/librustc_typeck/check/mod.rs | 18 ++-- src/librustc_typeck/check/pat.rs | 2 +- src/librustc_typeck/check/regionck.rs | 20 ++--- src/librustc_typeck/check/writeback.rs | 8 +- src/librustdoc/clean/mod.rs | 4 +- src/libsyntax/ast.rs | 22 ++--- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/ext/build.rs | 12 +-- src/libsyntax/mut_visit.rs | 12 +-- src/libsyntax/parse/attr.rs | 2 +- src/libsyntax/parse/diagnostics.rs | 34 ++++---- src/libsyntax/parse/parser.rs | 98 +++++++++++----------- src/libsyntax/parse/parser/expr.rs | 12 +-- src/libsyntax/parse/parser/item.rs | 10 +-- src/libsyntax/parse/parser/ty.rs | 2 +- src/libsyntax/print/pprust.rs | 18 ++-- src/libsyntax/visit.rs | 14 ++-- src/libsyntax_ext/deriving/generic/mod.rs | 4 +- src/libsyntax_ext/global_allocator.rs | 12 +-- .../async-await/no-args-non-move-async-closure.rs | 2 +- .../no-args-non-move-async-closure.stderr | 2 +- .../ui/generator/no-arguments-on-generators.rs | 2 +- .../ui/generator/no-arguments-on-generators.stderr | 2 +- 53 files changed, 379 insertions(+), 376 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index fa274f831b7..bbde3510e29 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -210,8 +210,8 @@ pub trait Visitor<'v> : Sized { } } - fn visit_arg(&mut self, arg: &'v Arg) { - walk_arg(self, arg) + fn visit_param(&mut self, param: &'v Param) { + walk_param(self, param) } /// Visits the top-level item and (optionally) nested items / impl items. See @@ -400,7 +400,7 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_hir_id } pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) { - walk_list!(visitor, visit_arg, &body.arguments); + walk_list!(visitor, visit_param, &body.params); visitor.visit_expr(&body.value); } @@ -454,10 +454,10 @@ pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id) } -pub fn walk_arg<'v, V: Visitor<'v>>(visitor: &mut V, arg: &'v Arg) { - visitor.visit_id(arg.hir_id); - visitor.visit_pat(&arg.pat); - walk_list!(visitor, visit_attribute, &arg.attrs); +pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param) { + visitor.visit_id(param.hir_id); + visitor.visit_pat(¶m.pat); + walk_list!(visitor, visit_attribute, ¶m.attrs); } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 7ec32106137..5e2aebfd318 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -510,12 +510,12 @@ impl<'a> LoweringContext<'a> { &f.generic_params ); // Mirrors visit::walk_fn_decl - for argument in &f.decl.inputs { + for parameter in &f.decl.inputs { // We don't lower the ids of argument patterns self.with_hir_id_owner(None, |this| { - this.visit_pat(&argument.pat); + this.visit_pat(¶meter.pat); }); - self.visit_ty(&argument.ty) + self.visit_ty(¶meter.ty) } self.visit_fn_ret_ty(&f.decl.output) } @@ -735,7 +735,7 @@ impl<'a> LoweringContext<'a> { /// /// Presuming that in-band lifetimes are enabled, then /// `self.anonymous_lifetime_mode` will be updated to match the - /// argument while `f` is running (and restored afterwards). + /// parameter while `f` is running (and restored afterwards). fn collect_in_band_defs( &mut self, parent_id: DefId, @@ -880,7 +880,7 @@ impl<'a> LoweringContext<'a> { /// /// Presuming that in-band lifetimes are enabled, then /// `self.anonymous_lifetime_mode` will be updated to match the - /// argument while `f` is running (and restored afterwards). + /// parameter while `f` is running (and restored afterwards). fn add_in_band_defs( &mut self, generics: &Generics, @@ -1080,7 +1080,7 @@ impl<'a> LoweringContext<'a> { ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => (true, ImplTraitContext::OpaqueTy(None)), - // We are in the argument position, but not within a dyn type: + // We are in the parameter position, but not within a dyn type: // // fn foo(x: impl Iterator) // @@ -1204,7 +1204,7 @@ impl<'a> LoweringContext<'a> { unsafety: this.lower_unsafety(f.unsafety), abi: f.abi, decl: this.lower_fn_decl(&f.decl, None, false, None), - arg_names: this.lower_fn_args_to_names(&f.decl), + param_names: this.lower_fn_params_to_names(&f.decl), })) }, ) @@ -2093,12 +2093,12 @@ impl<'a> LoweringContext<'a> { } } - fn lower_fn_args_to_names(&mut self, decl: &FnDecl) -> hir::HirVec { + fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> hir::HirVec { decl.inputs .iter() - .map(|arg| match arg.pat.node { + .map(|param| match param.pat.node { PatKind::Ident(_, ident, _) => ident, - _ => Ident::new(kw::Invalid, arg.pat.span), + _ => Ident::new(kw::Invalid, param.pat.span), }) .collect() } @@ -2136,11 +2136,11 @@ impl<'a> LoweringContext<'a> { let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| { decl.inputs .iter() - .map(|arg| { + .map(|param| { if let Some((_, ibty)) = &mut in_band_ty_params { - this.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty)) + this.lower_ty_direct(¶m.ty, ImplTraitContext::Universal(ibty)) } else { - this.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed()) + this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed()) } }) .collect::>() @@ -2205,7 +2205,7 @@ impl<'a> LoweringContext<'a> { // // type OpaqueTy = impl Future; // - // `inputs`: lowered types of arguments to the function (used to collect lifetimes) + // `inputs`: lowered types of parameters to the function (used to collect lifetimes) // `output`: unlowered output type (`T` in `-> T`) // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition) // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index 4f9a9ed5673..4e432f4981d 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -720,7 +720,7 @@ impl LoweringContext<'_> { ( // Disallow impl Trait in foreign items this.lower_fn_decl(fdec, None, false, None), - this.lower_fn_args_to_names(fdec), + this.lower_fn_params_to_names(fdec), ) }, ); @@ -827,7 +827,7 @@ impl LoweringContext<'_> { ), ), TraitItemKind::Method(ref sig, None) => { - let names = self.lower_fn_args_to_names(&sig.decl); + let names = self.lower_fn_params_to_names(&sig.decl); let (generics, sig) = self.lower_method_sig( &i.generics, sig, @@ -1028,10 +1028,10 @@ impl LoweringContext<'_> { } } - fn record_body(&mut self, arguments: HirVec, value: hir::Expr) -> hir::BodyId { + fn record_body(&mut self, params: HirVec, value: hir::Expr) -> hir::BodyId { let body = hir::Body { generator_kind: self.generator_kind, - arguments, + params, value, }; let id = body.id(); @@ -1041,21 +1041,21 @@ impl LoweringContext<'_> { fn lower_body( &mut self, - f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec, hir::Expr), + f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec, hir::Expr), ) -> hir::BodyId { let prev_gen_kind = self.generator_kind.take(); - let (arguments, result) = f(self); - let body_id = self.record_body(arguments, result); + let (parameters, result) = f(self); + let body_id = self.record_body(parameters, result); self.generator_kind = prev_gen_kind; body_id } - fn lower_arg(&mut self, arg: &Arg) -> hir::Arg { - hir::Arg { - attrs: self.lower_attrs(&arg.attrs), - hir_id: self.lower_node_id(arg.id), - pat: self.lower_pat(&arg.pat), - span: arg.span, + fn lower_param(&mut self, param: &Param) -> hir::Param { + hir::Param { + attrs: self.lower_attrs(¶m.attrs), + hir_id: self.lower_node_id(param.id), + pat: self.lower_pat(¶m.pat), + span: param.span, } } @@ -1065,7 +1065,7 @@ impl LoweringContext<'_> { body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, ) -> hir::BodyId { self.lower_body(|this| ( - decl.inputs.iter().map(|x| this.lower_arg(x)).collect(), + decl.inputs.iter().map(|x| this.lower_param(x)).collect(), body(this), )) } @@ -1093,10 +1093,10 @@ impl LoweringContext<'_> { }; self.lower_body(|this| { - let mut arguments: Vec = Vec::new(); + let mut parameters: Vec = Vec::new(); let mut statements: Vec = Vec::new(); - // Async function arguments are lowered into the closure body so that they are + // Async function parameters are lowered into the closure body so that they are // captured and so that the drop order matches the equivalent non-async functions. // // from: @@ -1121,13 +1121,13 @@ impl LoweringContext<'_> { // // If `` is a simple ident, then it is lowered to a single // `let = ;` statement as an optimization. - for (index, argument) in decl.inputs.iter().enumerate() { - let argument = this.lower_arg(argument); - let span = argument.pat.span; + for (index, parameter) in decl.inputs.iter().enumerate() { + let parameter = this.lower_param(parameter); + let span = parameter.pat.span; // Check if this is a binding pattern, if so, we can optimize and avoid adding a - // `let = __argN;` statement. In this case, we do not rename the argument. - let (ident, is_simple_argument) = match argument.pat.node { + // `let = __argN;` statement. In this case, we do not rename the parameter. + let (ident, is_simple_parameter) = match parameter.pat.node { hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _) => (ident, true), _ => { @@ -1142,32 +1142,32 @@ impl LoweringContext<'_> { let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None); - // Construct an argument representing `__argN: ` to replace the argument of the + // Construct a parameter representing `__argN: ` to replace the parameter of the // async function. // - // If this is the simple case, this argument will end up being the same as the - // original argument, but with a different pattern id. + // If this is the simple case, this parameter will end up being the same as the + // original parameter, but with a different pattern id. let mut stmt_attrs = ThinVec::new(); - stmt_attrs.extend(argument.attrs.iter().cloned()); - let (new_argument_pat, new_argument_id) = this.pat_ident(desugared_span, ident); - let new_argument = hir::Arg { - attrs: argument.attrs, - hir_id: argument.hir_id, - pat: new_argument_pat, - span: argument.span, + stmt_attrs.extend(parameter.attrs.iter().cloned()); + let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident); + let new_parameter = hir::Param { + attrs: parameter.attrs, + hir_id: parameter.hir_id, + pat: new_parameter_pat, + span: parameter.span, }; - if is_simple_argument { + if is_simple_parameter { // If this is the simple case, then we only insert one statement that is // `let = ;`. We re-use the original argument's pattern so that // `HirId`s are densely assigned. - let expr = this.expr_ident(desugared_span, ident, new_argument_id); + let expr = this.expr_ident(desugared_span, ident, new_parameter_id); let stmt = this.stmt_let_pat( stmt_attrs, desugared_span, Some(P(expr)), - argument.pat, + parameter.pat, hir::LocalSource::AsyncFn ); statements.push(stmt); @@ -1179,7 +1179,7 @@ impl LoweringContext<'_> { // let = __argN; // ``` // - // The first statement moves the argument into the closure and thus ensures + // The first statement moves the parameter into the closure and thus ensures // that the drop order is correct. // // The second statement creates the bindings that the user wrote. @@ -1189,7 +1189,7 @@ impl LoweringContext<'_> { // statement. let (move_pat, move_id) = this.pat_ident_binding_mode( desugared_span, ident, hir::BindingAnnotation::Mutable); - let move_expr = this.expr_ident(desugared_span, ident, new_argument_id); + let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id); let move_stmt = this.stmt_let_pat( ThinVec::new(), desugared_span, @@ -1199,13 +1199,13 @@ impl LoweringContext<'_> { ); // Construct the `let = __argN;` statement. We re-use the original - // argument's pattern so that `HirId`s are densely assigned. + // parameter's pattern so that `HirId`s are densely assigned. let pattern_expr = this.expr_ident(desugared_span, ident, move_id); let pattern_stmt = this.stmt_let_pat( stmt_attrs, desugared_span, Some(P(pattern_expr)), - argument.pat, + parameter.pat, hir::LocalSource::AsyncFn ); @@ -1213,7 +1213,7 @@ impl LoweringContext<'_> { statements.push(pattern_stmt); }; - arguments.push(new_argument); + parameters.push(new_parameter); } let async_expr = this.make_async_expr( @@ -1222,7 +1222,7 @@ impl LoweringContext<'_> { let body = this.lower_block_with_stmts(body, false, statements); this.expr_block(body, ThinVec::new()) }); - (HirVec::from(arguments), this.expr(body.span, async_expr, ThinVec::new())) + (HirVec::from(parameters), this.expr(body.span, async_expr, ThinVec::new())) }) } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index effe2c0cc6a..773bb8dde06 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -363,11 +363,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.currently_in_body = prev_in_body; } - fn visit_arg(&mut self, arg: &'hir Arg) { - let node = Node::Arg(arg); - self.insert(arg.pat.span, arg.hir_id, node); - self.with_parent(arg.hir_id, |this| { - intravisit::walk_arg(this, arg); + fn visit_param(&mut self, param: &'hir Param) { + let node = Node::Param(param); + self.insert(param.pat.span, param.hir_id, node); + self.with_parent(param.hir_id, |this| { + intravisit::walk_param(this, param); }); } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index f80e527dfd9..eb8be6e6e3c 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -360,7 +360,7 @@ impl<'hir> Map<'hir> { Node::Pat(_) | Node::Binding(_) | Node::Local(_) | - Node::Arg(_) | + Node::Param(_) | Node::Arm(_) | Node::Lifetime(_) | Node::Visibility(_) | @@ -964,7 +964,7 @@ impl<'hir> Map<'hir> { pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { self.read(id); // reveals attributes on the node let attrs = match self.find_entry(id).map(|entry| entry.node) { - Some(Node::Arg(a)) => Some(&a.attrs[..]), + Some(Node::Param(a)) => Some(&a.attrs[..]), Some(Node::Local(l)) => Some(&l.attrs[..]), Some(Node::Item(i)) => Some(&i.attrs[..]), Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]), @@ -1028,7 +1028,7 @@ impl<'hir> Map<'hir> { pub fn span(&self, hir_id: HirId) -> Span { self.read(hir_id); // reveals span from node match self.find_entry(hir_id).map(|entry| entry.node) { - Some(Node::Arg(arg)) => arg.span, + Some(Node::Param(param)) => param.span, Some(Node::Item(item)) => item.span, Some(Node::ForeignItem(foreign_item)) => foreign_item.span, Some(Node::TraitItem(trait_method)) => trait_method.span, @@ -1223,7 +1223,7 @@ impl<'hir> print::PpAnn for Map<'hir> { Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat) + Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat) } } } @@ -1231,7 +1231,7 @@ impl<'hir> print::PpAnn for Map<'hir> { impl<'a> print::State<'a> { pub fn print_node(&mut self, node: Node<'_>) { match node { - Node::Arg(a) => self.print_arg(&a), + Node::Param(a) => self.print_param(&a), Node::Item(a) => self.print_item(&a), Node::ForeignItem(a) => self.print_foreign_item(&a), Node::TraitItem(a) => self.print_trait_item(a), @@ -1373,8 +1373,8 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { Some(Node::Pat(_)) => { format!("pat {}{}", map.hir_to_pretty_string(id), id_str) } - Some(Node::Arg(_)) => { - format!("arg {}{}", map.hir_to_pretty_string(id), id_str) + Some(Node::Param(_)) => { + format!("param {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Arm(_)) => { format!("arm {}{}", map.hir_to_pretty_string(id), id_str) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 98304818852..d2c45a5af85 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1030,7 +1030,7 @@ pub enum Mutability { } impl Mutability { - /// Returns `MutMutable` only if both arguments are mutable. + /// Returns `MutMutable` only if both `self` and `other` are mutable. pub fn and(self, other: Self) -> Self { match self { MutMutable => other, @@ -1324,7 +1324,7 @@ pub struct BodyId { /// /// Here, the `Body` associated with `foo()` would contain: /// -/// - an `arguments` array containing the `(x, y)` pattern +/// - an `params` array containing the `(x, y)` pattern /// - a `value` containing the `x + y` expression (maybe wrapped in a block) /// - `generator_kind` would be `None` /// @@ -1332,7 +1332,7 @@ pub struct BodyId { /// map using `body_owner_def_id()`. #[derive(RustcEncodable, RustcDecodable, Debug)] pub struct Body { - pub arguments: HirVec, + pub params: HirVec, pub value: Expr, pub generator_kind: Option, } @@ -1644,7 +1644,7 @@ pub enum LocalSource { /// A desugared `for _ in _ { .. }` loop. ForLoopDesugar, /// When lowering async functions, we create locals within the `async move` so that - /// all arguments are dropped after the future is polled. + /// all parameters are dropped after the future is polled. /// /// ```ignore (pseudo-Rust) /// async fn foo( @ x: Type) { @@ -1940,7 +1940,7 @@ pub struct BareFnTy { pub abi: Abi, pub generic_params: HirVec, pub decl: P, - pub arg_names: HirVec, + pub param_names: HirVec, } #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] @@ -2027,9 +2027,9 @@ pub struct InlineAsm { pub dialect: AsmDialect, } -/// Represents an argument in a function header. +/// Represents a parameter in a function header. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] -pub struct Arg { +pub struct Param { pub attrs: HirVec, pub hir_id: HirId, pub pat: P, @@ -2039,9 +2039,9 @@ pub struct Arg { /// Represents the header (not the body) of a function declaration. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct FnDecl { - /// The types of the function's arguments. + /// The types of the function's parameters. /// - /// Additional argument data is stored in the function's [body](Body::arguments). + /// Additional argument data is stored in the function's [body](Body::parameters). pub inputs: HirVec, pub output: FunctionRetTy, pub c_variadic: bool, @@ -2721,7 +2721,7 @@ impl CodegenFnAttrs { #[derive(Copy, Clone, Debug)] pub enum Node<'hir> { - Arg(&'hir Arg), + Param(&'hir Param), Item(&'hir Item), ForeignItem(&'hir ForeignItem), TraitItem(&'hir TraitItem), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 632a13f9183..21cc72efee4 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -33,7 +33,7 @@ pub enum Nested { TraitItem(hir::TraitItemId), ImplItem(hir::ImplItemId), Body(hir::BodyId), - BodyArgPat(hir::BodyId, usize) + BodyParamPat(hir::BodyId, usize) } pub trait PpAnn { @@ -62,7 +62,7 @@ impl PpAnn for hir::Crate { Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat) + Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat) } } } @@ -318,7 +318,7 @@ impl<'a> State<'a> { } hir::TyKind::BareFn(ref f) => { self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &f.generic_params, - &f.arg_names[..]); + &f.param_names[..]); } hir::TyKind::Def(..) => {}, hir::TyKind::Path(ref qpath) => { @@ -1290,7 +1290,7 @@ impl<'a> State<'a> { hir::ExprKind::Closure(capture_clause, ref decl, body, _fn_decl_span, _gen) => { self.print_capture_clause(capture_clause); - self.print_closure_args(&decl, body); + self.print_closure_params(&decl, body); self.s.space(); // this is a bare expression @@ -1775,7 +1775,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - pub fn print_arg(&mut self, arg: &hir::Arg) { + pub fn print_param(&mut self, arg: &hir::Param) { self.print_outer_attributes(&arg.attrs); self.print_pat(&arg.pat); } @@ -1864,7 +1864,7 @@ impl<'a> State<'a> { s.s.word(":"); s.s.space(); } else if let Some(body_id) = body_id { - s.ann.nested(s, Nested::BodyArgPat(body_id, i)); + s.ann.nested(s, Nested::BodyParamPat(body_id, i)); s.s.word(":"); s.s.space(); } @@ -1881,13 +1881,13 @@ impl<'a> State<'a> { self.print_where_clause(&generics.where_clause) } - fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) { + fn print_closure_params(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) { self.s.word("|"); let mut i = 0; self.commasep(Inconsistent, &decl.inputs, |s, ty| { s.ibox(INDENT_UNIT); - s.ann.nested(s, Nested::BodyArgPat(body_id, i)); + s.ann.nested(s, Nested::BodyParamPat(body_id, i)); i += 1; if let hir::TyKind::Infer = ty.node { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 60b338010b0..fb981d96112 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -331,13 +331,13 @@ impl<'a> HashStable> for hir::Body { hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Body { - arguments, + params, value, generator_kind, } = self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| { - arguments.hash_stable(hcx, hasher); + params.hash_stable(hcx, hasher); value.hash_stable(hcx, hasher); generator_kind.hash_stable(hcx, hasher); }); diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 5e0f973fdd3..7068fe3601a 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -78,12 +78,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { } fn visit_body(&mut self, body: &'tcx Body) { - for argument in &body.arguments { + for param in &body.params { if let (None, Some(ty)) = ( self.found_arg_pattern, - self.node_matches_type(argument.hir_id), + self.node_matches_type(param.hir_id), ) { - self.found_arg_pattern = Some(&*argument.pat); + self.found_arg_pattern = Some(&*param.pat); self.found_ty = Some(ty); } } diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index 6bd2c04d512..979815fa7f1 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -2,7 +2,7 @@ //! where both the regions are anonymous. use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::error_reporting::nice_region_error::util::AnonymousArgInfo; +use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; use crate::util::common::ErrorReported; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -59,13 +59,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let ty_sub = self.find_anon_type(sub, &bregion_sub)?; debug!( - "try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}", + "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}", ty_sub, sup, bregion_sup ); debug!( - "try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}", + "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}", ty_sup, sub, bregion_sub @@ -74,24 +74,24 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let (ty_sup, ty_fndecl_sup) = ty_sup; let (ty_sub, ty_fndecl_sub) = ty_sub; - let AnonymousArgInfo { - arg: anon_arg_sup, .. - } = self.find_arg_with_region(sup, sup)?; - let AnonymousArgInfo { - arg: anon_arg_sub, .. - } = self.find_arg_with_region(sub, sub)?; + let AnonymousParamInfo { + param: anon_param_sup, .. + } = self.find_param_with_region(sup, sup)?; + let AnonymousParamInfo { + param: anon_param_sub, .. + } = self.find_param_with_region(sub, sub)?; let sup_is_ret_type = self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup); let sub_is_ret_type = self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - let span_label_var1 = match anon_arg_sup.pat.simple_ident() { + let span_label_var1 = match anon_param_sup.pat.simple_ident() { Some(simple_ident) => format!(" from `{}`", simple_ident), None => String::new(), }; - let span_label_var2 = match anon_arg_sub.pat.simple_ident() { + let span_label_var2 = match anon_param_sub.pat.simple_ident() { Some(simple_ident) => format!(" into `{}`", simple_ident), None => String::new(), }; diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 51bee49b70f..604115cfc37 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -6,7 +6,7 @@ use crate::ty; use errors::{Applicability, DiagnosticBuilder}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// When given a `ConcreteFailure` for a function with arguments containing a named region and + /// When given a `ConcreteFailure` for a function with parameters containing a named region and /// an anonymous region, emit an descriptive diagnostic error. pub(super) fn try_report_named_anon_conflict(&self) -> Option> { let (span, sub, sup) = self.get_regions(); @@ -24,23 +24,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced // with the named one.//scope_def_id - let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub) + let (named, anon, anon_param_info, region_info) = if self.is_named_region(sub) && self.tcx().is_suitable_region(sup).is_some() - && self.find_arg_with_region(sup, sub).is_some() + && self.find_param_with_region(sup, sub).is_some() { ( sub, sup, - self.find_arg_with_region(sup, sub).unwrap(), + self.find_param_with_region(sup, sub).unwrap(), self.tcx().is_suitable_region(sup).unwrap(), ) } else if self.is_named_region(sup) && self.tcx().is_suitable_region(sub).is_some() - && self.find_arg_with_region(sub, sup).is_some() + && self.find_param_with_region(sub, sup).is_some() { ( sup, sub, - self.find_arg_with_region(sub, sup).unwrap(), + self.find_param_with_region(sub, sup).unwrap(), self.tcx().is_suitable_region(sub).unwrap(), ) } else { @@ -49,20 +49,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { debug!("try_report_named_anon_conflict: named = {:?}", named); debug!( - "try_report_named_anon_conflict: anon_arg_info = {:?}", - anon_arg_info + "try_report_named_anon_conflict: anon_param_info = {:?}", + anon_param_info ); debug!( "try_report_named_anon_conflict: region_info = {:?}", region_info ); - let (arg, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = ( - anon_arg_info.arg, - anon_arg_info.arg_ty, - anon_arg_info.arg_ty_span, - anon_arg_info.bound_region, - anon_arg_info.is_first, + let (param, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = ( + anon_param_info.param, + anon_param_info.param_ty, + anon_param_info.param_ty_span, + anon_param_info.bound_region, + anon_param_info.is_first, region_info.def_id, region_info.is_impl_item, ); @@ -95,7 +95,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - let (error_var, span_label_var) = match arg.pat.simple_ident() { + let (error_var, span_label_var) = match param.pat.simple_ident() { Some(simple_ident) => ( format!("the type of `{}`", simple_ident), format!("the type of `{}`", simple_ident), diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs index f33f9173926..668c99da003 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs @@ -10,37 +10,37 @@ use syntax_pos::Span; // The struct contains the information about the anonymous region // we are searching for. #[derive(Debug)] -pub(super) struct AnonymousArgInfo<'tcx> { - // the argument corresponding to the anonymous region - pub arg: &'tcx hir::Arg, - // the type corresponding to the anonymopus region argument - pub arg_ty: Ty<'tcx>, +pub(super) struct AnonymousParamInfo<'tcx> { + // the parameter corresponding to the anonymous region + pub param: &'tcx hir::Param, + // the type corresponding to the anonymopus region parameter + pub param_ty: Ty<'tcx>, // the ty::BoundRegion corresponding to the anonymous region pub bound_region: ty::BoundRegion, - // arg_ty_span contains span of argument type - pub arg_ty_span : Span, + // param_ty_span contains span of parameter type + pub param_ty_span : Span, // corresponds to id the argument is the first parameter // in the declaration pub is_first: bool, } impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - // This method walks the Type of the function body arguments using + // This method walks the Type of the function body parameters using // `fold_regions()` function and returns the - // &hir::Arg of the function argument corresponding to the anonymous + // &hir::Param of the function parameter corresponding to the anonymous // region and the Ty corresponding to the named region. // Currently only the case where the function declaration consists of // one named region and one anonymous region is handled. // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` - // Here, we would return the hir::Arg for y, we return the type &'a + // Here, we would return the hir::Param for y, we return the type &'a // i32, which is the type of y but with the anonymous region replaced // with 'a, the corresponding bound region and is_first which is true if - // the hir::Arg is the first argument in the function declaration. - pub(super) fn find_arg_with_region( + // the hir::Param is the first parameter in the function declaration. + pub(super) fn find_param_with_region( &self, anon_region: Region<'tcx>, replace_region: Region<'tcx>, - ) -> Option> { + ) -> Option> { let (id, bound_region) = match *anon_region { ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), ty::ReEarlyBound(ebr) => ( @@ -57,16 +57,16 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let owner_id = hir.body_owner(body_id); let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); if let Some(tables) = self.tables { - body.arguments + body.params .iter() .enumerate() - .filter_map(|(index, arg)| { + .filter_map(|(index, param)| { // May return None; sometimes the tables are not yet populated. let ty_hir_id = fn_decl.inputs[index].hir_id; - let arg_ty_span = hir.span(ty_hir_id); - let ty = tables.node_type_opt(arg.hir_id)?; + let param_ty_span = hir.span(ty_hir_id); + let ty = tables.node_type_opt(param.hir_id)?; let mut found_anon_region = false; - let new_arg_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { + let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { if *r == *anon_region { found_anon_region = true; replace_region @@ -76,10 +76,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }); if found_anon_region { let is_first = index == 0; - Some(AnonymousArgInfo { - arg: arg, - arg_ty: new_arg_ty, - arg_ty_span : arg_ty_span, + Some(AnonymousParamInfo { + param: param, + param_ty: new_param_ty, + param_ty_span : param_ty_span, bound_region: bound_region, is_first: is_first, }) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 8126db14292..affda256322 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -966,10 +966,10 @@ for LateContextAndPass<'a, 'tcx, T> { self.context.tables = old_tables; } - fn visit_arg(&mut self, arg: &'tcx hir::Arg) { - self.with_lint_attrs(arg.hir_id, &arg.attrs, |cx| { - lint_callback!(cx, check_arg, arg); - hir_visit::walk_arg(cx, arg); + fn visit_param(&mut self, param: &'tcx hir::Param) { + self.with_lint_attrs(param.hir_id, ¶m.attrs, |cx| { + lint_callback!(cx, check_param, param); + hir_visit::walk_param(cx, param); }); } @@ -1163,10 +1163,10 @@ for LateContextAndPass<'a, 'tcx, T> { } impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> { - fn visit_arg(&mut self, arg: &'a ast::Arg) { - self.with_lint_attrs(arg.id, &arg.attrs, |cx| { - run_early_pass!(cx, check_arg, arg); - ast_visit::walk_arg(cx, arg); + fn visit_param(&mut self, param: &'a ast::Param) { + self.with_lint_attrs(param.id, ¶m.attrs, |cx| { + run_early_pass!(cx, check_param, param); + ast_visit::walk_param(cx, param); }); } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 7e2707b98d5..a3518b2b478 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -206,7 +206,7 @@ macro_rules! declare_lint_pass { macro_rules! late_lint_methods { ($macro:path, $args:tt, [$hir:tt]) => ( $macro!($args, [$hir], [ - fn check_arg(a: &$hir hir::Arg); + fn check_param(a: &$hir hir::Param); fn check_body(a: &$hir hir::Body); fn check_body_post(a: &$hir hir::Body); fn check_name(a: Span, b: ast::Name); @@ -349,7 +349,7 @@ macro_rules! declare_combined_late_lint_pass { macro_rules! early_lint_methods { ($macro:path, $args:tt) => ( $macro!($args, [ - fn check_arg(a: &ast::Arg); + fn check_param(a: &ast::Param); fn check_ident(a: ast::Ident); fn check_crate(a: &ast::Crate); fn check_crate_post(a: &ast::Crate); @@ -792,9 +792,9 @@ impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } - fn visit_arg(&mut self, arg: &'tcx hir::Arg) { - self.with_lint_attrs(arg.hir_id, &arg.attrs, |builder| { - intravisit::walk_arg(builder, arg); + fn visit_param(&mut self, param: &'tcx hir::Param) { + self.with_lint_attrs(param.hir_id, ¶m.attrs, |builder| { + intravisit::walk_param(builder, param); }); } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a274d7bbee5..222c2a405d6 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -313,9 +313,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { pub fn consume_body(&mut self, body: &hir::Body) { debug!("consume_body(body={:?})", body); - for arg in &body.arguments { - let arg_ty = return_if_err!(self.mc.pat_ty_adjusted(&arg.pat)); - debug!("consume_body: arg_ty = {:?}", arg_ty); + for param in &body.params { + let param_ty = return_if_err!(self.mc.pat_ty_adjusted(¶m.pat)); + debug!("consume_body: param_ty = {:?}", param_ty); let fn_body_scope_r = self.tcx().mk_region(ty::ReScope( @@ -323,13 +323,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { id: body.value.hir_id.local_id, data: region::ScopeData::Node })); - let arg_cmt = Rc::new(self.mc.cat_rvalue( - arg.hir_id, - arg.pat.span, - fn_body_scope_r, // Args live only as long as the fn body. - arg_ty)); + let param_cmt = Rc::new(self.mc.cat_rvalue( + param.hir_id, + param.pat.span, + fn_body_scope_r, // Parameters live only as long as the fn body. + param_ty)); - self.walk_irrefutable_pat(arg_cmt, &arg.pat); + self.walk_irrefutable_pat(param_cmt, ¶m.pat); } self.consume_expr(&body.value); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 9c9e8c0bca3..00013bfc574 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -242,7 +242,7 @@ struct LocalInfo { #[derive(Copy, Clone, Debug)] enum VarKind { - Arg(HirId, ast::Name), + Param(HirId, ast::Name), Local(LocalInfo), CleanExit } @@ -298,7 +298,7 @@ impl IrMaps<'tcx> { self.num_vars += 1; match vk { - Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => { + Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) => { self.variable_map.insert(node_id, v); }, CleanExit => {} @@ -320,7 +320,7 @@ impl IrMaps<'tcx> { fn variable_name(&self, var: Variable) -> String { match self.var_kinds[var.get()] { - Local(LocalInfo { name, .. }) | Arg(_, name) => { + Local(LocalInfo { name, .. }) | Param(_, name) => { name.to_string() }, CleanExit => "".to_owned() @@ -330,7 +330,7 @@ impl IrMaps<'tcx> { fn variable_is_shorthand(&self, var: Variable) -> bool { match self.var_kinds[var.get()] { Local(LocalInfo { is_shorthand, .. }) => is_shorthand, - Arg(..) | CleanExit => false + Param(..) | CleanExit => false } } @@ -371,13 +371,13 @@ fn visit_fn<'tcx>( let body = ir.tcx.hir().body(body_id); - for arg in &body.arguments { - let is_shorthand = match arg.pat.node { + for param in &body.params { + let is_shorthand = match param.pat.node { crate::hir::PatKind::Struct(..) => true, _ => false, }; - arg.pat.each_binding(|_bm, hir_id, _x, ident| { - debug!("adding argument {:?}", hir_id); + param.pat.each_binding(|_bm, hir_id, _x, ident| { + debug!("adding parameters {:?}", hir_id); let var = if is_shorthand { Local(LocalInfo { id: hir_id, @@ -385,7 +385,7 @@ fn visit_fn<'tcx>( is_shorthand: true, }) } else { - Arg(hir_id, ident.name) + Param(hir_id, ident.name) }; fn_maps.add_variable(var); }) @@ -1525,8 +1525,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) { - for arg in &body.arguments { - arg.pat.each_binding(|_bm, hir_id, _, ident| { + for param in &body.params { + param.pat.each_binding(|_bm, hir_id, _, ident| { let sp = ident.span; let var = self.variable(hir_id, sp); // Ignore unused self. diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 3d100d2fbf8..28aa86ef9af 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1383,8 +1383,8 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // The arguments and `self` are parented to the fn. self.cx.var_parent = self.cx.parent.take(); - for argument in &body.arguments { - self.visit_pat(&argument.pat); + for param in &body.params { + self.visit_pat(¶m.pat); } // The body of the every fn is a root scope. diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index f5b0af61693..8836a632a7c 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2557,7 +2557,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } = info; let help_name = if let Some(ident) = parent.and_then(|body| { - self.tcx.hir().body(body).arguments[index].pat.simple_ident() + self.tcx.hir().body(body).params[index].pat.simple_ident() }) { format!("`{}`", ident) } else { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba92e851141..93742c83be4 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1044,7 +1044,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { node: hir::ExprKind::Closure(_, ref _decl, id, span, _), .. }) => { - (self.tcx.sess.source_map().def_span(span), self.tcx.hir().body(id).arguments.iter() + (self.tcx.sess.source_map().def_span(span), + self.tcx.hir().body(id).params.iter() .map(|arg| { if let hir::Pat { node: hir::PatKind::Tuple(ref args, _), diff --git a/src/librustc_ast_borrowck/dataflow.rs b/src/librustc_ast_borrowck/dataflow.rs index 94849728a93..3a4c8c92476 100644 --- a/src/librustc_ast_borrowck/dataflow.rs +++ b/src/librustc_ast_borrowck/dataflow.rs @@ -186,8 +186,8 @@ fn build_local_id_to_index(body: Option<&hir::Body>, index: &'a mut FxHashMap>, } let mut formals = Formals { entry: entry, index: index }; - for arg in &body.arguments { - formals.visit_pat(&arg.pat); + for param in &body.params { + formals.visit_pat(¶m.pat); } impl<'a, 'v> Visitor<'v> for Formals<'a> { fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 7aeeef00ea9..3fbd11bd22a 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -166,7 +166,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, // a `fn` when encoding, so the dep-tracking wouldn't work. // This is only used by rustdoc anyway, which shouldn't have // incremental recompilation ever enabled. - fn_arg_names => { cdata.get_fn_arg_names(def_id.index) } + fn_arg_names => { cdata.get_fn_param_names(def_id.index) } rendered_const => { cdata.get_rendered_const(def_id.index) } impl_parent => { cdata.get_parent_impl(def_id.index) } trait_of_item => { cdata.get_trait_of_item(def_id.index) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5b9cb966af2..ede31fe69b6 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1150,14 +1150,14 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_fn_arg_names(&self, id: DefIndex) -> Vec { - let arg_names = match self.entry(id).kind { + pub fn get_fn_param_names(&self, id: DefIndex) -> Vec { + let param_names = match self.entry(id).kind { EntryKind::Fn(data) | - EntryKind::ForeignFn(data) => data.decode(self).arg_names, - EntryKind::Method(data) => data.decode(self).fn_data.arg_names, + EntryKind::ForeignFn(data) => data.decode(self).param_names, + EntryKind::Method(data) => data.decode(self).fn_data.param_names, _ => Lazy::empty(), }; - arg_names.decode(self).collect() + param_names.decode(self).collect() } pub fn exported_symbols( diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 1797d774615..0eafcebefd7 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -869,18 +869,18 @@ impl EncodeContext<'tcx> { } ty::AssocKind::Method => { let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node { - let arg_names = match *m { + let param_names = match *m { hir::TraitMethod::Required(ref names) => { - self.encode_fn_arg_names(names) + self.encode_fn_param_names(names) } hir::TraitMethod::Provided(body) => { - self.encode_fn_arg_names_for_body(body) + self.encode_fn_param_names_for_body(body) } }; FnData { constness: hir::Constness::NotConst, - arg_names, - sig: self.lazy(tcx.fn_sig(def_id)), + param_names, + sig: self.lazy(&tcx.fn_sig(def_id)), } } else { bug!() @@ -976,8 +976,8 @@ impl EncodeContext<'tcx> { let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { FnData { constness: sig.header.constness, - arg_names: self.encode_fn_arg_names_for_body(body), - sig: self.lazy(tcx.fn_sig(def_id)), + param_names: self.encode_fn_param_names_for_body(body), + sig: self.lazy(&tcx.fn_sig(def_id)), } } else { bug!() @@ -1033,11 +1033,11 @@ impl EncodeContext<'tcx> { } } - fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId) + fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[ast::Name]> { self.tcx.dep_graph.with_ignore(|| { let body = self.tcx.hir().body(body_id); - self.lazy(body.arguments.iter().map(|arg| { + self.lazy(body.params.iter().map(|arg| { match arg.pat.node { PatKind::Binding(_, _, ident, _) => ident.name, _ => kw::Invalid, @@ -1046,7 +1046,7 @@ impl EncodeContext<'tcx> { }) } - fn encode_fn_arg_names(&mut self, param_names: &[ast::Ident]) -> Lazy<[ast::Name]> { + fn encode_fn_param_names(&mut self, param_names: &[ast::Ident]) -> Lazy<[ast::Name]> { self.lazy(param_names.iter().map(|ident| ident.name)) } @@ -1122,7 +1122,7 @@ impl EncodeContext<'tcx> { hir::ItemKind::Fn(_, header, .., body) => { let data = FnData { constness: header.constness, - arg_names: self.encode_fn_arg_names_for_body(body), + param_names: self.encode_fn_param_names_for_body(body), sig: self.lazy(tcx.fn_sig(def_id)), }; @@ -1663,7 +1663,7 @@ impl EncodeContext<'tcx> { hir::ForeignItemKind::Fn(_, ref names, _) => { let data = FnData { constness: hir::Constness::NotConst, - arg_names: self.encode_fn_arg_names(names), + param_names: self.encode_fn_param_names(names), sig: self.lazy(tcx.fn_sig(def_id)), }; EntryKind::ForeignFn(self.lazy(data)) diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 72a4b527c93..1a5887bbf4e 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -295,7 +295,7 @@ pub struct MacroDef { #[derive(RustcEncodable, RustcDecodable)] pub struct FnData<'tcx> { pub constness: hir::Constness, - pub arg_names: Lazy<[ast::Name]>, + pub param_names: Lazy<[ast::Name]>, pub sig: Lazy>, } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 61be17327ff..7ab0bf7d66a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -94,7 +94,7 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { let body = tcx.hir().body(body_id); let explicit_arguments = - body.arguments + body.params .iter() .enumerate() .map(|(index, arg)| { @@ -511,7 +511,7 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, abi: Abi) -> bool { /////////////////////////////////////////////////////////////////////////// /// the main entry point for building MIR for a function -struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Arg>, Option); +struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Param>, Option); fn construct_fn<'a, 'tcx, A>( hir: Cx<'a, 'tcx>, diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 17fd9377a16..5352888006c 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -91,9 +91,9 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { fn visit_body(&mut self, body: &'tcx hir::Body) { intravisit::walk_body(self, body); - for arg in &body.arguments { - self.check_irrefutable(&arg.pat, "function argument"); - self.check_patterns(false, slice::from_ref(&arg.pat)); + for param in &body.params { + self.check_irrefutable(¶m.pat, "function argument"); + self.check_patterns(false, slice::from_ref(¶m.pat)); } } } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 7e03df5b75b..a5924efefc2 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -94,9 +94,9 @@ impl<'k> StatCollector<'k> { } impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { - fn visit_arg(&mut self, arg: &'v hir::Arg) { - self.record("Arg", Id::Node(arg.hir_id), arg); - hir_visit::walk_arg(self, arg) + fn visit_param(&mut self, param: &'v hir::Param) { + self.record("Param", Id::Node(param.hir_id), param); + hir_visit::walk_param(self, param) } fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 9068605b075..d1fd51a97f6 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -230,7 +230,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { + fn process_formals(&mut self, formals: &'l [ast::Param], qualname: &str) { for arg in formals { self.visit_pat(&arg.pat); let mut collector = PathCollector::new(); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 0bbbbb8249c..92ccd4f49f6 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -32,7 +32,7 @@ use syntax::source_map::Spanned; use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::print::pprust; use syntax::visit::{self, Visitor}; -use syntax::print::pprust::{arg_to_string, ty_to_string}; +use syntax::print::pprust::{param_to_string, ty_to_string}; use syntax_pos::*; use dump_visitor::DumpVisitor; @@ -934,7 +934,7 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { sig.push('('); sig.push_str(&decl.inputs .iter() - .map(arg_to_string) + .map(param_to_string) .collect::>() .join(", ")); sig.push(')'); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 0efc433341c..63137bad52f 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -224,13 +224,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// fn takes_ref(_: &Foo) {} /// let ref opt = Some(Foo); /// - /// opt.map(|arg| takes_ref(arg)); + /// opt.map(|param| takes_ref(param)); /// ``` - /// Suggest using `opt.as_ref().map(|arg| takes_ref(arg));` instead. + /// Suggest using `opt.as_ref().map(|param| takes_ref(param));` instead. /// /// It only checks for `Option` and `Result` and won't work with /// ``` - /// opt.map(|arg| { takes_ref(arg) }); + /// opt.map(|param| { takes_ref(param) }); /// ``` fn can_use_as_ref( &self, @@ -247,13 +247,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let local_parent = self.tcx.hir().get_parent_node(local_id); - let arg_hir_id = match self.tcx.hir().find(local_parent) { - Some(Node::Arg(hir::Arg { hir_id, .. })) => hir_id, + let param_hir_id = match self.tcx.hir().find(local_parent) { + Some(Node::Param(hir::Param { hir_id, .. })) => hir_id, _ => return None }; - let arg_parent = self.tcx.hir().get_parent_node(*arg_hir_id); - let (expr_hir_id, closure_fn_decl) = match self.tcx.hir().find(arg_parent) { + let param_parent = self.tcx.hir().get_parent_node(*param_hir_id); + let (expr_hir_id, closure_fn_decl) = match self.tcx.hir().find(param_parent) { Some(Node::Expr( hir::Expr { hir_id, node: hir::ExprKind::Closure(_, decl, ..), .. } )) => (hir_id, decl), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c4dbe97a7bd..2a3c422fe04 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1102,19 +1102,19 @@ fn check_fn<'a, 'tcx>( GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id, }.visit_body(body); // Add formal parameters. - for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) { + for (param_ty, param) in fn_sig.inputs().iter().zip(&body.params) { // Check the pattern. - fcx.check_pat_top(&arg.pat, arg_ty, None); + fcx.check_pat_top(¶m.pat, param_ty, None); // Check that argument is Sized. // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. - if arg.pat.simple_ident().is_none() && !fcx.tcx.features().unsized_locals { - fcx.require_type_is_sized(arg_ty, decl.output.span(), traits::SizedArgumentType); + if param.pat.simple_ident().is_none() && !fcx.tcx.features().unsized_locals { + fcx.require_type_is_sized(param_ty, decl.output.span(), traits::SizedArgumentType); } - fcx.write_ty(arg.hir_id, arg_ty); + fcx.write_ty(param.hir_id, param_ty); } inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); @@ -3952,8 +3952,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .. })) => { let body = hir.body(*body_id); - sugg_call = body.arguments.iter() - .map(|arg| match &arg.pat.node { + sugg_call = body.params.iter() + .map(|param| match ¶m.pat.node { hir::PatKind::Binding(_, _, ident, None) if ident.name != kw::SelfLower => ident.to_string(), _ => "_".to_string(), @@ -3970,8 +3970,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(*closure_span, "closure defined here"); msg = "call this closure"; let body = hir.body(*body_id); - sugg_call = body.arguments.iter() - .map(|arg| match &arg.pat.node { + sugg_call = body.params.iter() + .map(|param| match ¶m.pat.node { hir::PatKind::Binding(_, _, ident, None) if ident.name != kw::SelfLower => ident.to_string(), _ => "_".to_string(), diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 3f6fc95360a..4cf0df308fb 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -468,7 +468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let binding_parent = tcx.hir().get(binding_parent_id); debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent); match binding_parent { - hir::Node::Arg(hir::Arg { span, .. }) => { + hir::Node::Param(hir::Param { span, .. }) => { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { err.span_suggestion( *span, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 3f9e662c6f4..fc01a820e23 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -347,12 +347,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { ); self.outlives_environment .save_implied_bounds(body_id.hir_id); - self.link_fn_args( + self.link_fn_params( region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Node, }, - &body.arguments, + &body.params, ); self.visit_body(body); self.visit_region_obligations(body_id.hir_id); @@ -1078,16 +1078,16 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { /// Computes the guarantors for any ref bindings in a match and /// then ensures that the lifetime of the resulting pointer is /// linked to the lifetime of its guarantor (if any). - fn link_fn_args(&self, body_scope: region::Scope, args: &[hir::Arg]) { - debug!("regionck::link_fn_args(body_scope={:?})", body_scope); - for arg in args { - let arg_ty = self.node_ty(arg.hir_id); + fn link_fn_params(&self, body_scope: region::Scope, params: &[hir::Param]) { + debug!("regionck::link_fn_params(body_scope={:?})", body_scope); + for param in params { + let param_ty = self.node_ty(param.hir_id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); - let arg_cmt = self.with_mc(|mc| { - Rc::new(mc.cat_rvalue(arg.hir_id, arg.pat.span, re_scope, arg_ty)) + let param_cmt = self.with_mc(|mc| { + Rc::new(mc.cat_rvalue(param.hir_id, param.pat.span, re_scope, param_ty)) }); - debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, arg_cmt, arg); - self.link_pattern(arg_cmt, &arg.pat); + debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param); + self.link_pattern(param_cmt, ¶m.pat); } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index a88e32eb34d..487dc8ec2ae 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -39,8 +39,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); - for arg in &body.arguments { - wbcx.visit_node_id(arg.pat.span, arg.hir_id); + for param in &body.params { + wbcx.visit_node_id(param.pat.span, param.hir_id); } // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_id) { @@ -245,8 +245,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { match e.node { hir::ExprKind::Closure(_, _, body, _, _) => { let body = self.fcx.tcx.hir().body(body); - for arg in &body.arguments { - self.visit_node_id(e.span, arg.hir_id); + for param in &body.params { + self.visit_node_id(e.span, param.hir_id); } self.visit_body(body); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ba792a413b3..629892e6072 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2120,7 +2120,7 @@ impl<'a> Clean for (&'a [hir::Ty], hir::BodyId) { Arguments { values: self.0.iter().enumerate().map(|(i, ty)| { Argument { - name: name_from_pat(&body.arguments[i].pat), + name: name_from_pat(&body.params[i].pat), type_: ty.clean(cx), } }).collect() @@ -3804,7 +3804,7 @@ pub struct BareFunctionDecl { impl Clean for hir::BareFnTy { fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, || { - (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx)) + (self.generic_params.clean(cx), (&*self.decl, &self.param_names[..]).clean(cx)) }); BareFunctionDecl { unsafety: self.unsafety, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 50e428ea0cc..6be00bcef45 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1789,11 +1789,11 @@ pub struct InlineAsm { pub dialect: AsmDialect, } -/// An argument in a function header. +/// A parameter in a function header. /// /// E.g., `bar: usize` as in `fn foo(bar: usize)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct Arg { +pub struct Param { pub attrs: ThinVec, pub ty: P, pub pat: P, @@ -1816,7 +1816,7 @@ pub enum SelfKind { pub type ExplicitSelf = Spanned; -impl Arg { +impl Param { pub fn to_self(&self) -> Option { if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.node { if ident.name == kw::SelfLower { @@ -1843,14 +1843,14 @@ impl Arg { } } - pub fn from_self(attrs: ThinVec, eself: ExplicitSelf, eself_ident: Ident) -> Arg { + pub fn from_self(attrs: ThinVec, eself: ExplicitSelf, eself_ident: Ident) -> Param { let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, node: TyKind::ImplicitSelf, span, }); - let arg = |mutbl, ty| Arg { + let param = |mutbl, ty| Param { attrs, pat: P(Pat { id: DUMMY_NODE_ID, @@ -1862,9 +1862,9 @@ impl Arg { id: DUMMY_NODE_ID, }; match eself.node { - SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty), - SelfKind::Value(mutbl) => arg(mutbl, infer_ty), - SelfKind::Region(lt, mutbl) => arg( + SelfKind::Explicit(ty, mutbl) => param(mutbl, ty), + SelfKind::Value(mutbl) => param(mutbl, infer_ty), + SelfKind::Region(lt, mutbl) => param( Mutability::Immutable, P(Ty { id: DUMMY_NODE_ID, @@ -1887,17 +1887,17 @@ impl Arg { /// E.g., `fn foo(bar: baz)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct FnDecl { - pub inputs: Vec, + pub inputs: Vec, pub output: FunctionRetTy, pub c_variadic: bool, } impl FnDecl { pub fn get_self(&self) -> Option { - self.inputs.get(0).and_then(Arg::to_self) + self.inputs.get(0).and_then(Param::to_self) } pub fn has_self(&self) -> bool { - self.inputs.get(0).map(Arg::is_self).unwrap_or(false) + self.inputs.get(0).map(Param::is_self).unwrap_or(false) } } diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index bcf03b5237a..0e5cfa73a9e 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -714,7 +714,7 @@ macro_rules! derive_has_attrs { derive_has_attrs! { Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm, - ast::Field, ast::FieldPat, ast::Variant, ast::Arg + ast::Field, ast::FieldPat, ast::Variant, ast::Param } pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index e2ac4d573a1..e894fd17ff5 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -655,7 +655,7 @@ impl<'a> ExtCtxt<'a> { body: P) -> P { let fn_decl = self.fn_decl( - ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(), + ids.iter().map(|id| self.param(span, *id, self.ty_infer(span))).collect(), ast::FunctionRetTy::Default(span)); // FIXME -- We are using `span` as the span of the `|...|` @@ -693,9 +693,9 @@ impl<'a> ExtCtxt<'a> { self.lambda1(span, self.expr_block(self.block(span, stmts)), ident) } - pub fn arg(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Arg { + pub fn param(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Param { let arg_pat = self.pat_ident(span, ident); - ast::Arg { + ast::Param { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat: arg_pat, @@ -705,7 +705,7 @@ impl<'a> ExtCtxt<'a> { } // FIXME: unused `self` - pub fn fn_decl(&self, inputs: Vec, output: ast::FunctionRetTy) -> P { + pub fn fn_decl(&self, inputs: Vec, output: ast::FunctionRetTy) -> P { P(ast::FnDecl { inputs, output, @@ -731,7 +731,7 @@ impl<'a> ExtCtxt<'a> { pub fn item_fn_poly(&self, span: Span, name: Ident, - inputs: Vec , + inputs: Vec , output: P, generics: Generics, body: P) -> P { @@ -752,7 +752,7 @@ impl<'a> ExtCtxt<'a> { pub fn item_fn(&self, span: Span, name: Ident, - inputs: Vec , + inputs: Vec , output: P, body: P ) -> P { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 414d234e434..e14ca4b06a0 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -225,8 +225,8 @@ pub trait MutVisitor: Sized { noop_visit_attribute(at, self); } - fn flat_map_arg(&mut self, arg: Arg) -> SmallVec<[Arg; 1]> { - noop_flat_map_arg(arg, self) + fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { + noop_flat_map_param(param, self) } fn visit_generics(&mut self, generics: &mut Generics) { @@ -587,14 +587,14 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_flat_map_arg(mut arg: Arg, vis: &mut T) -> SmallVec<[Arg; 1]> { - let Arg { attrs, id, pat, span, ty } = &mut arg; +pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> { + let Param { attrs, id, pat, span, ty } = &mut param; vis.visit_id(id); visit_thin_attrs(attrs, vis); vis.visit_pat(pat); vis.visit_span(span); vis.visit_ty(ty); - smallvec![arg] + smallvec![param] } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { @@ -720,7 +720,7 @@ pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) pub fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { let FnDecl { inputs, output, c_variadic: _ } = decl.deref_mut(); - inputs.flat_map_in_place(|arg| vis.flat_map_arg(arg)); + inputs.flat_map_in_place(|param| vis.flat_map_param(param)); match output { FunctionRetTy::Default(span) => vis.visit_span(span), FunctionRetTy::Ty(ty) => vis.visit_ty(ty), diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index c703058e795..671178223f5 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -19,7 +19,7 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ permitted in this context"; impl<'a> Parser<'a> { - crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec> { + crate fn parse_param_attributes(&mut self) -> PResult<'a, Vec> { let attrs = self.parse_outer_attributes()?; self.sess.gated_spans.param_attrs.borrow_mut() .extend(attrs.iter().map(|a| a.span)); diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 1fbf28fb830..d4e661d1a38 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1,5 +1,5 @@ use crate::ast::{ - self, Arg, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, + self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData, }; use crate::feature_gate::{feature_err, UnstableFeatures}; @@ -18,7 +18,7 @@ use log::{debug, trace}; use std::mem; /// Creates a placeholder argument. -crate fn dummy_arg(ident: Ident) -> Arg { +crate fn dummy_arg(ident: Ident) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), @@ -29,7 +29,7 @@ crate fn dummy_arg(ident: Ident) -> Arg { span: ident.span, id: ast::DUMMY_NODE_ID }; - Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) } + Param { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) } } pub enum Error { @@ -1183,7 +1183,7 @@ impl<'a> Parser<'a> { Err(err) } - crate fn eat_incorrect_doc_comment_for_arg_type(&mut self) { + crate fn eat_incorrect_doc_comment_for_param_type(&mut self) { if let token::DocComment(_) = self.token.kind { self.struct_span_err( self.token.span, @@ -1211,7 +1211,7 @@ impl<'a> Parser<'a> { } } - crate fn argument_without_type( + crate fn parameter_without_type( &mut self, err: &mut DiagnosticBuilder<'_>, pat: P, @@ -1286,13 +1286,13 @@ impl<'a> Parser<'a> { Ok((pat, ty)) } - crate fn recover_bad_self_arg( + crate fn recover_bad_self_param( &mut self, - mut arg: ast::Arg, + mut param: ast::Param, is_trait_item: bool, - ) -> PResult<'a, ast::Arg> { - let sp = arg.pat.span; - arg.ty.node = TyKind::Err; + ) -> PResult<'a, ast::Param> { + let sp = param.pat.span; + param.ty.node = TyKind::Err; let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function"); if is_trait_item { err.span_label(sp, "must be the first associated function parameter"); @@ -1301,7 +1301,7 @@ impl<'a> Parser<'a> { err.note("`self` is only valid as the first parameter of an associated function"); } err.emit(); - Ok(arg) + Ok(param) } crate fn consume_block(&mut self, delim: token::DelimToken) { @@ -1344,15 +1344,15 @@ impl<'a> Parser<'a> { err } - /// Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors. + /// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors. /// /// This is necessary because at this point we don't know whether we parsed a function with - /// anonymous arguments or a function with names but no types. In order to minimize - /// unecessary errors, we assume the arguments are in the shape of `fn foo(a, b, c)` where - /// the arguments are *names* (so we don't emit errors about not being able to find `b` in + /// anonymous parameters or a function with names but no types. In order to minimize + /// unecessary errors, we assume the parameters are in the shape of `fn foo(a, b, c)` where + /// the parameters are *names* (so we don't emit errors about not being able to find `b` in /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, - /// we deduplicate them to not complain about duplicated argument names. - crate fn deduplicate_recovered_arg_names(&self, fn_inputs: &mut Vec) { + /// we deduplicate them to not complain about duplicated parameter names. + crate fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec) { let mut seen_inputs = FxHashSet::default(); for input in fn_inputs.iter_mut() { let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = ( diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 25ad2d4404c..bee47df942a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -10,7 +10,7 @@ pub use path::PathStyle; mod stmt; mod generics; -use crate::ast::{self, AttrStyle, Attribute, Arg, BindingMode, StrStyle, SelfKind}; +use crate::ast::{self, AttrStyle, Attribute, Param, BindingMode, StrStyle, SelfKind}; use crate::ast::{FnDecl, Ident, IsAsync, MacDelimiter, Mutability, TyKind}; use crate::ast::{Visibility, VisibilityKind, Unsafety, CrateSugar}; use crate::source_map::{self, respan}; @@ -970,27 +970,27 @@ impl<'a> Parser<'a> { /// Skips unexpected attributes and doc comments in this position and emits an appropriate /// error. - /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general( + /// This version of parse param doesn't necessarily require identifier names. + fn parse_param_general( &mut self, is_trait_item: bool, allow_c_variadic: bool, is_name_required: impl Fn(&token::Token) -> bool, - ) -> PResult<'a, Arg> { + ) -> PResult<'a, Param> { let lo = self.token.span; - let attrs = self.parse_arg_attributes()?; - if let Some(mut arg) = self.parse_self_arg()? { - arg.attrs = attrs.into(); - return self.recover_bad_self_arg(arg, is_trait_item); + let attrs = self.parse_param_attributes()?; + if let Some(mut param) = self.parse_self_param()? { + param.attrs = attrs.into(); + return self.recover_bad_self_param(param, is_trait_item); } let is_name_required = is_name_required(&self.token); let (pat, ty) = if is_name_required || self.is_named_argument() { - debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required); + debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); let pat = self.parse_fn_param_pat()?; if let Err(mut err) = self.expect(&token::Colon) { - if let Some(ident) = self.argument_without_type( + if let Some(ident) = self.parameter_without_type( &mut err, pat, is_name_required, @@ -1003,12 +1003,12 @@ impl<'a> Parser<'a> { } } - self.eat_incorrect_doc_comment_for_arg_type(); + self.eat_incorrect_doc_comment_for_param_type(); (pat, self.parse_ty_common(true, true, allow_c_variadic)?) } else { - debug!("parse_arg_general ident_to_pat"); + debug!("parse_param_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment_for_arg_type(); + self.eat_incorrect_doc_comment_for_param_type(); let mut ty = self.parse_ty_common(true, true, allow_c_variadic); if ty.is_ok() && self.token != token::Comma && self.token != token::CloseDelim(token::Paren) { @@ -1039,7 +1039,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.token.span); - Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, span, ty }) + Ok(Param { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, span, ty }) } /// Parses mutability (`mut` or nothing). @@ -1185,26 +1185,26 @@ impl<'a> Parser<'a> { } - fn parse_fn_args(&mut self, named_args: bool, allow_c_variadic: bool) - -> PResult<'a, (Vec , bool)> { + fn parse_fn_params(&mut self, named_params: bool, allow_c_variadic: bool) + -> PResult<'a, (Vec , bool)> { let sp = self.token.span; let mut c_variadic = false; - let (args, _): (Vec>, _) = self.parse_paren_comma_seq(|p| { + let (params, _): (Vec>, _) = self.parse_paren_comma_seq(|p| { let do_not_enforce_named_arguments_for_c_variadic = |token: &token::Token| -> bool { if token == &token::DotDotDot { false } else { - named_args + named_params } }; - match p.parse_arg_general( + match p.parse_param_general( false, allow_c_variadic, do_not_enforce_named_arguments_for_c_variadic ) { - Ok(arg) => { - if let TyKind::CVarArgs = arg.ty.node { + Ok(param) => { + if let TyKind::CVarArgs = param.ty.node { c_variadic = true; if p.token != token::CloseDelim(token::Paren) { let span = p.token.span; @@ -1212,10 +1212,10 @@ impl<'a> Parser<'a> { "`...` must be the last argument of a C-variadic function"); Ok(None) } else { - Ok(Some(arg)) + Ok(Some(param)) } } else { - Ok(Some(arg)) + Ok(Some(param)) } }, Err(mut e) => { @@ -1230,20 +1230,20 @@ impl<'a> Parser<'a> { } })?; - let args: Vec<_> = args.into_iter().filter_map(|x| x).collect(); + let params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); - if c_variadic && args.len() <= 1 { + if c_variadic && params.len() <= 1 { self.span_err(sp, "C-variadic function must be declared with at least one named argument"); } - Ok((args, c_variadic)) + Ok((params, c_variadic)) } - /// Returns the parsed optional self argument and whether a self shortcut was used. + /// Returns the parsed optional self parameter and whether a self shortcut was used. /// - /// See `parse_self_arg_with_attrs` to collect attributes. - fn parse_self_arg(&mut self) -> PResult<'a, Option> { + /// See `parse_self_param_with_attrs` to collect attributes. + fn parse_self_param(&mut self) -> PResult<'a, Option> { let expect_ident = |this: &mut Self| match this.token.kind { // Preserve hygienic context. token::Ident(name, _) => @@ -1348,49 +1348,51 @@ impl<'a> Parser<'a> { }; let eself = source_map::respan(eself_lo.to(eself_hi), eself); - Ok(Some(Arg::from_self(ThinVec::default(), eself, eself_ident))) + Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident))) } - /// Returns the parsed optional self argument with attributes and whether a self + /// Returns the parsed optional self parameter with attributes and whether a self /// shortcut was used. - fn parse_self_arg_with_attrs(&mut self) -> PResult<'a, Option> { - let attrs = self.parse_arg_attributes()?; - let arg_opt = self.parse_self_arg()?; - Ok(arg_opt.map(|mut arg| { - arg.attrs = attrs.into(); - arg + fn parse_self_parameter_with_attrs(&mut self) -> PResult<'a, Option> { + let attrs = self.parse_param_attributes()?; + let param_opt = self.parse_self_param()?; + Ok(param_opt.map(|mut param| { + param.attrs = attrs.into(); + param })) } /// Parses the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self(&mut self, parse_arg_fn: F) -> PResult<'a, P> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, + fn parse_fn_decl_with_self(&mut self, parse_param_fn: F) -> PResult<'a, P> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, Param>, { self.expect(&token::OpenDelim(token::Paren))?; // Parse optional self argument. - let self_arg = self.parse_self_arg_with_attrs()?; + let self_param = self.parse_self_parameter_with_attrs()?; // Parse the rest of the function parameter list. let sep = SeqSep::trailing_allowed(token::Comma); - let (mut fn_inputs, recovered) = if let Some(self_arg) = self_arg { + let (mut fn_inputs, recovered) = if let Some(self_param) = self_param { if self.check(&token::CloseDelim(token::Paren)) { - (vec![self_arg], false) + (vec![self_param], false) } else if self.eat(&token::Comma) { - let mut fn_inputs = vec![self_arg]; + let mut fn_inputs = vec![self_param]; let (mut input, _, recovered) = self.parse_seq_to_before_end( - &token::CloseDelim(token::Paren), sep, parse_arg_fn)?; + &token::CloseDelim(token::Paren), sep, parse_param_fn)?; fn_inputs.append(&mut input); (fn_inputs, recovered) } else { match self.expect_one_of(&[], &[]) { Err(err) => return Err(err), - Ok(recovered) => (vec![self_arg], recovered), + Ok(recovered) => (vec![self_param], recovered), } } } else { let (input, _, recovered) = - self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?; + self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), + sep, + parse_param_fn)?; (input, recovered) }; @@ -1398,8 +1400,8 @@ impl<'a> Parser<'a> { // Parse closing paren and return type. self.expect(&token::CloseDelim(token::Paren))?; } - // Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors. - self.deduplicate_recovered_arg_names(&mut fn_inputs); + // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. + self.deduplicate_recovered_params_names(&mut fn_inputs); Ok(P(FnDecl { inputs: fn_inputs, diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index f7c090b5135..5b9f0f1df67 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -7,7 +7,7 @@ use crate::maybe_recover_from_interpolated_ty_qpath; use crate::ptr::P; use crate::ast::{self, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode}; use crate::ast::{Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm}; -use crate::ast::{Ty, TyKind, FunctionRetTy, Arg, FnDecl}; +use crate::ast::{Ty, TyKind, FunctionRetTy, Param, FnDecl}; use crate::ast::{BinOpKind, BinOp, UnOp}; use crate::ast::{Mac, AnonConst, Field}; @@ -1157,7 +1157,7 @@ impl<'a> Parser<'a> { &[&token::BinOp(token::Or), &token::OrOr], SeqSep::trailing_allowed(token::Comma), TokenExpectType::NoExpect, - |p| p.parse_fn_block_arg() + |p| p.parse_fn_block_param() )?.0; self.expect_or()?; args @@ -1172,10 +1172,10 @@ impl<'a> Parser<'a> { })) } - /// Parses an argument in a lambda header (e.g., `|arg, arg|`). - fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { + /// Parses a parameter in a lambda header (e.g., `|arg, arg|`). + fn parse_fn_block_param(&mut self) -> PResult<'a, Param> { let lo = self.token.span; - let attrs = self.parse_arg_attributes()?; + let attrs = self.parse_param_attributes()?; let pat = self.parse_pat(PARAM_EXPECTED)?; let t = if self.eat(&token::Colon) { self.parse_ty()? @@ -1187,7 +1187,7 @@ impl<'a> Parser<'a> { }) }; let span = lo.to(self.token.span); - Ok(Arg { + Ok(Param { attrs: attrs.into(), ty: t, pat, diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 03d7e922123..59a3ade9c30 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -422,7 +422,7 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { let ident = self.parse_ident().unwrap(); self.bump(); // `(` - let kw_name = if let Ok(Some(_)) = self.parse_self_arg_with_attrs() + let kw_name = if let Ok(Some(_)) = self.parse_self_parameter_with_attrs() .map_err(|mut e| e.cancel()) { "method" @@ -475,7 +475,7 @@ impl<'a> Parser<'a> { self.eat_to_tokens(&[&token::Gt]); self.bump(); // `>` let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) { - if let Ok(Some(_)) = self.parse_self_arg_with_attrs() + if let Ok(Some(_)) = self.parse_self_parameter_with_attrs() .map_err(|mut e| e.cancel()) { ("fn", "method", false) @@ -861,7 +861,7 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; let decl = self.parse_fn_decl_with_self(|p| { - p.parse_arg_general(true, false, |_| true) + p.parse_param_general(true, false, |_| true) })?; generics.where_clause = self.parse_where_clause()?; *at_end = true; @@ -1040,7 +1040,7 @@ impl<'a> Parser<'a> { // We don't allow argument names to be left off in edition 2018. let is_name_required = p.token.span.rust_2018(); - p.parse_arg_general(true, false, |_| is_name_required) + p.parse_param_general(true, false, |_| is_name_required) })?; generics.where_clause = self.parse_where_clause()?; @@ -1291,7 +1291,7 @@ impl<'a> Parser<'a> { /// Parses the argument list and result type of a function declaration. fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P> { - let (args, c_variadic) = self.parse_fn_args(true, allow_c_variadic)?; + let (args, c_variadic) = self.parse_fn_params(true, allow_c_variadic)?; let ret_ty = self.parse_ret_ty(true)?; Ok(P(FnDecl { diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index 337702b8d30..465e31ac57e 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -292,7 +292,7 @@ impl<'a> Parser<'a> { }; self.expect_keyword(kw::Fn)?; - let (inputs, c_variadic) = self.parse_fn_args(false, true)?; + let (inputs, c_variadic) = self.parse_fn_params(false, true)?; let ret_ty = self.parse_ret_ty(false)?; let decl = P(FnDecl { inputs, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 83a926a6217..bead941b20d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -418,8 +418,8 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String { to_string(|s| s.print_attribute(attr)) } -pub fn arg_to_string(arg: &ast::Arg) -> String { - to_string(|s| s.print_arg(arg, false)) +pub fn param_to_string(arg: &ast::Param) -> String { + to_string(|s| s.print_param(arg, false)) } fn foreign_item_to_string(arg: &ast::ForeignItem) -> String { @@ -2101,7 +2101,7 @@ impl<'a> State<'a> { self.print_asyncness(asyncness); self.print_capture_clause(capture_clause); - self.print_fn_block_args(decl); + self.print_fn_block_params(decl); self.s.space(); self.print_expr(body); self.end(); // need to close a box @@ -2536,21 +2536,21 @@ impl<'a> State<'a> { self.print_ident(name); } self.print_generic_params(&generics.params); - self.print_fn_args_and_ret(decl); + self.print_fn_params_and_ret(decl); self.print_where_clause(&generics.where_clause) } - crate fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl) { + crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl) { self.popen(); - self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false)); + self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, false)); self.pclose(); self.print_fn_output(decl) } - crate fn print_fn_block_args(&mut self, decl: &ast::FnDecl) { + crate fn print_fn_block_params(&mut self, decl: &ast::FnDecl) { self.s.word("|"); - self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true)); + self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, true)); self.s.word("|"); if let ast::FunctionRetTy::Default(..) = decl.output { @@ -2759,7 +2759,7 @@ impl<'a> State<'a> { self.print_type(&mt.ty) } - crate fn print_arg(&mut self, input: &ast::Arg, is_closure: bool) { + crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) { self.ibox(INDENT_UNIT); self.print_outer_attributes_inline(&input.attrs); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 86f6d36c3c6..ce1568316f8 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -66,7 +66,7 @@ pub trait Visitor<'ast>: Sized { fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } fn visit_stmt(&mut self, s: &'ast Stmt) { walk_stmt(self, s) } - fn visit_arg(&mut self, arg: &'ast Arg) { walk_arg(self, arg) } + fn visit_param(&mut self, param: &'ast Param) { walk_param(self, param) } fn visit_arm(&mut self, a: &'ast Arm) { walk_arm(self, a) } fn visit_pat(&mut self, p: &'ast Pat) { walk_pat(self, p) } fn visit_anon_const(&mut self, c: &'ast AnonConst) { walk_anon_const(self, c) } @@ -555,8 +555,8 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionR } pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { - for arg in &function_declaration.inputs { - visitor.visit_arg(arg); + for param in &function_declaration.inputs { + visitor.visit_param(param); } visitor.visit_fn_ret_ty(&function_declaration.output); } @@ -824,10 +824,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr_post(expression) } -pub fn walk_arg<'a, V: Visitor<'a>>(visitor: &mut V, arg: &'a Arg) { - walk_list!(visitor, visit_attribute, arg.attrs.iter()); - visitor.visit_pat(&arg.pat); - visitor.visit_ty(&arg.ty); +pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) { + walk_list!(visitor, visit_attribute, param.attrs.iter()); + visitor.visit_pat(¶m.pat); + visitor.visit_ty(¶m.ty); } pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1475bac0688..6fd763f5a91 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -929,10 +929,10 @@ impl<'a> MethodDef<'a> { let args = { let self_args = explicit_self.map(|explicit_self| { let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span); - ast::Arg::from_self(ThinVec::default(), explicit_self, ident) + ast::Param::from_self(ThinVec::default(), explicit_self, ident) }); let nonself_args = arg_types.into_iter() - .map(|(name, ty)| cx.arg(trait_.span, name, ty)); + .map(|(name, ty)| cx.param(trait_.span, name, ty)); self_args.into_iter().chain(nonself_args).collect() }; diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index 97b8087ad15..f4af1699cd6 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -1,5 +1,5 @@ use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety}; -use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident}; +use syntax::ast::{self, Param, Attribute, Expr, FnHeader, Generics, Ident}; use syntax::attr::check_builtin_macro_attribute; use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; use syntax::ext::base::{Annotatable, ExtCtxt}; @@ -114,7 +114,7 @@ impl AllocFnFactory<'_, '_> { fn arg_ty( &self, ty: &AllocatorTy, - args: &mut Vec, + args: &mut Vec, ident: &mut dyn FnMut() -> Ident, ) -> P { match *ty { @@ -123,8 +123,8 @@ impl AllocFnFactory<'_, '_> { let ty_usize = self.cx.ty_path(usize); let size = ident(); let align = ident(); - args.push(self.cx.arg(self.span, size, ty_usize.clone())); - args.push(self.cx.arg(self.span, align, ty_usize)); + args.push(self.cx.param(self.span, size, ty_usize.clone())); + args.push(self.cx.param(self.span, align, ty_usize)); let layout_new = self.cx.std_path(&[ Symbol::intern("alloc"), @@ -140,14 +140,14 @@ impl AllocFnFactory<'_, '_> { AllocatorTy::Ptr => { let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + args.push(self.cx.param(self.span, ident, self.ptr_u8())); let arg = self.cx.expr_ident(self.span, ident); self.cx.expr_cast(self.span, arg, self.ptr_u8()) } AllocatorTy::Usize => { let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.usize())); + args.push(self.cx.param(self.span, ident, self.usize())); self.cx.expr_ident(self.span, ident) } diff --git a/src/test/ui/async-await/no-args-non-move-async-closure.rs b/src/test/ui/async-await/no-args-non-move-async-closure.rs index 0ca50807f26..3b15f35c260 100644 --- a/src/test/ui/async-await/no-args-non-move-async-closure.rs +++ b/src/test/ui/async-await/no-args-non-move-async-closure.rs @@ -4,5 +4,5 @@ fn main() { let _ = async |x: u8| {}; - //~^ ERROR `async` non-`move` closures with arguments are not currently supported + //~^ ERROR `async` non-`move` closures with parameters are not currently supported } diff --git a/src/test/ui/async-await/no-args-non-move-async-closure.stderr b/src/test/ui/async-await/no-args-non-move-async-closure.stderr index 1b4b86210f8..c58210b997b 100644 --- a/src/test/ui/async-await/no-args-non-move-async-closure.stderr +++ b/src/test/ui/async-await/no-args-non-move-async-closure.stderr @@ -1,4 +1,4 @@ -error[E0708]: `async` non-`move` closures with arguments are not currently supported +error[E0708]: `async` non-`move` closures with parameters are not currently supported --> $DIR/no-args-non-move-async-closure.rs:6:13 | LL | let _ = async |x: u8| {}; diff --git a/src/test/ui/generator/no-arguments-on-generators.rs b/src/test/ui/generator/no-arguments-on-generators.rs index 344c1179be9..a2632a4bd7d 100644 --- a/src/test/ui/generator/no-arguments-on-generators.rs +++ b/src/test/ui/generator/no-arguments-on-generators.rs @@ -1,7 +1,7 @@ #![feature(generators)] fn main() { - let gen = |start| { //~ ERROR generators cannot have explicit arguments + let gen = |start| { //~ ERROR generators cannot have explicit parameters yield; }; } diff --git a/src/test/ui/generator/no-arguments-on-generators.stderr b/src/test/ui/generator/no-arguments-on-generators.stderr index 23ae21585fd..8f993b27ce2 100644 --- a/src/test/ui/generator/no-arguments-on-generators.stderr +++ b/src/test/ui/generator/no-arguments-on-generators.stderr @@ -1,4 +1,4 @@ -error[E0628]: generators cannot have explicit arguments +error[E0628]: generators cannot have explicit parameters --> $DIR/no-arguments-on-generators.rs:4:15 | LL | let gen = |start| { -- cgit 1.4.1-3-g733a5 From dbbe3363c94b120d1eba9cba01dadddd862716b8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 27 Aug 2019 19:51:21 +0200 Subject: Ensure 'let mut ;' where ':pat' is banned. --- src/libsyntax/parse/parser/pat.rs | 9 +++++++++ src/test/ui/parser/mut-patterns.rs | 8 ++++++++ src/test/ui/parser/mut-patterns.stderr | 11 ++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 7b228a700a7..08934e85330 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -384,6 +384,7 @@ impl<'a> Parser<'a> { }) } + /// Parse a mutable binding with the `mut` token already eaten. fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> { let mut_span = self.prev_span; @@ -393,6 +394,14 @@ impl<'a> Parser<'a> { self.recover_additional_muts(); + // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. + if let token::Interpolated(ref nt) = self.token.kind { + if let token::NtPat(_) = **nt { + self.expected_ident_found().emit(); + } + } + + // Parse the pattern we hope to be an identifier. let mut pat = self.parse_pat(Some("identifier"))?; // Add `mut` to any binding in the parsed pattern. diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index 87e127f9d36..0c78ca726e0 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -32,4 +32,12 @@ pub fn main() { let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) //~^ ERROR `mut` must be attached to each individual binding = W(0, W(1, W(2, W(3, B { f: Box::new(4u8) })))); + + // Make sure we don't accidentally allow `mut $p` where `$p:pat`. + macro_rules! foo { + ($p:pat) => { + let mut $p = 0; //~ ERROR expected identifier, found `x` + } + } + foo!(x); } diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index a251e2908f0..a1293129e2e 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -64,5 +64,14 @@ error: `mut` must be attached to each individual binding LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` -error: aborting due to 9 previous errors +error: expected identifier, found `x` + --> $DIR/mut-patterns.rs:39:21 + | +LL | let mut $p = 0; + | ^^ expected identifier +... +LL | foo!(x); + | -------- in this macro invocation + +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 42e895d4d99ec7724f3efd632f52170f3f99a5aa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 27 Aug 2019 23:44:44 +0200 Subject: Improve 'mut ' diagnostic. --- src/libsyntax/parse/parser/pat.rs | 54 +++++++++++++++++++------------ src/test/ui/parser/issue-32501.rs | 2 +- src/test/ui/parser/issue-32501.stderr | 6 ++-- src/test/ui/parser/mut-patterns.rs | 3 ++ src/test/ui/parser/mut-patterns.stderr | 46 +++++++++++++++++++------- src/test/ui/self/self_type_keyword.rs | 2 +- src/test/ui/self/self_type_keyword.stderr | 6 ++-- 7 files changed, 82 insertions(+), 37 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 08934e85330..1ffb112a5e8 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -405,22 +405,13 @@ impl<'a> Parser<'a> { let mut pat = self.parse_pat(Some("identifier"))?; // Add `mut` to any binding in the parsed pattern. - struct AddMut; - impl MutVisitor for AddMut { - fn visit_pat(&mut self, pat: &mut P) { - if let PatKind::Ident(BindingMode::ByValue(ref mut m), ..) = pat.node { - *m = Mutability::Mutable; - } - noop_visit_pat(pat, self); - } - } - AddMut.visit_pat(&mut pat); + let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat); // Unwrap; If we don't have `mut $ident`, error. let pat = pat.into_inner(); match &pat.node { PatKind::Ident(..) => {} - _ => self.ban_mut_general_pat(mut_span, &pat), + _ => self.ban_mut_general_pat(mut_span, &pat, changed_any_binding), } Ok(pat.node) @@ -442,17 +433,40 @@ impl<'a> Parser<'a> { self.parse_pat_ident(BindingMode::ByRef(Mutability::Mutable)) } + /// Turn all by-value immutable bindings in a pattern into mutable bindings. + /// Returns `true` if any change was made. + fn make_all_value_bindings_mutable(pat: &mut P) -> bool { + struct AddMut(bool); + impl MutVisitor for AddMut { + fn visit_pat(&mut self, pat: &mut P) { + if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Immutable), ..) + = pat.node + { + *m = Mutability::Mutable; + self.0 = true; + } + noop_visit_pat(pat, self); + } + } + + let mut add_mut = AddMut(false); + add_mut.visit_pat(pat); + add_mut.0 + } + /// Error on `mut $pat` where `$pat` is not an ident. - fn ban_mut_general_pat(&self, lo: Span, pat: &Pat) { + fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) { let span = lo.to(pat.span); - self.struct_span_err(span, "`mut` must be attached to each individual binding") - .span_suggestion( - span, - "add `mut` to each binding", - pprust::pat_to_string(&pat), - Applicability::MachineApplicable, - ) - .emit(); + let fix = pprust::pat_to_string(&pat); + let (problem, suggestion) = if changed_any_binding { + ("`mut` must be attached to each individual binding", "add `mut` to each binding") + } else { + ("`mut` must be followed by a named binding", "remove the `mut` prefix") + }; + self.struct_span_err(span, problem) + .span_suggestion(span, suggestion, fix, Applicability::MachineApplicable) + .note("`mut` may be followed by `variable` and `variable @ pattern`") + .emit() } /// Eat any extraneous `mut`s and error + recover if we ate any. diff --git a/src/test/ui/parser/issue-32501.rs b/src/test/ui/parser/issue-32501.rs index 695baf81872..500242030c6 100644 --- a/src/test/ui/parser/issue-32501.rs +++ b/src/test/ui/parser/issue-32501.rs @@ -5,5 +5,5 @@ fn main() { let mut b = 0; let mut _b = 0; let mut _ = 0; - //~^ ERROR `mut` must be attached to each individual binding + //~^ ERROR `mut` must be followed by a named binding } diff --git a/src/test/ui/parser/issue-32501.stderr b/src/test/ui/parser/issue-32501.stderr index f5d3300cf9c..d53302449a8 100644 --- a/src/test/ui/parser/issue-32501.stderr +++ b/src/test/ui/parser/issue-32501.stderr @@ -1,8 +1,10 @@ -error: `mut` must be attached to each individual binding +error: `mut` must be followed by a named binding --> $DIR/issue-32501.rs:7:9 | LL | let mut _ = 0; - | ^^^^^ help: add `mut` to each binding: `_` + | ^^^^^ help: remove the `mut` prefix: `_` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: aborting due to previous error diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index 0c78ca726e0..d46186a0fea 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -6,6 +6,9 @@ #![allow(warnings)] pub fn main() { + let mut _ = 0; //~ ERROR `mut` must be followed by a named binding + let mut (_, _) = (0, 0); //~ ERROR `mut` must be followed by a named binding + let mut mut x = 0; //~^ ERROR `mut` on a binding may not be repeated //~| remove the additional `mut`s diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index a1293129e2e..18ffaa52558 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -1,29 +1,49 @@ +error: `mut` must be followed by a named binding + --> $DIR/mut-patterns.rs:9:9 + | +LL | let mut _ = 0; + | ^^^^^ help: remove the `mut` prefix: `_` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: `mut` must be followed by a named binding + --> $DIR/mut-patterns.rs:10:9 + | +LL | let mut (_, _) = (0, 0); + | ^^^^^^^^^^ help: remove the `mut` prefix: `(_, _)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:9:13 + --> $DIR/mut-patterns.rs:12:13 | LL | let mut mut x = 0; | ^^^ help: remove the additional `mut`s error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:14:9 + --> $DIR/mut-patterns.rs:17:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:18:9 + --> $DIR/mut-patterns.rs:21:9 | LL | let mut Foo { x } = Foo { x: 3 }; | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:23:13 + --> $DIR/mut-patterns.rs:26:13 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^ help: remove the additional `mut`s error: expected identifier, found reserved keyword `yield` - --> $DIR/mut-patterns.rs:23:17 + --> $DIR/mut-patterns.rs:26:17 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found reserved keyword @@ -33,7 +53,7 @@ LL | let mut mut r#yield(become, await) = r#yield(0, 0); | ^^^^^^^ error: expected identifier, found reserved keyword `become` - --> $DIR/mut-patterns.rs:23:23 + --> $DIR/mut-patterns.rs:26:23 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^ expected identifier, found reserved keyword @@ -43,7 +63,7 @@ LL | let mut mut yield(r#become, await) = r#yield(0, 0); | ^^^^^^^^ error: expected identifier, found reserved keyword `await` - --> $DIR/mut-patterns.rs:23:31 + --> $DIR/mut-patterns.rs:26:31 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found reserved keyword @@ -53,19 +73,23 @@ LL | let mut mut yield(become, r#await) = r#yield(0, 0); | ^^^^^^^ error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:23:9 + --> $DIR/mut-patterns.rs:26:9 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:32:9 + --> $DIR/mut-patterns.rs:35:9 | LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: expected identifier, found `x` - --> $DIR/mut-patterns.rs:39:21 + --> $DIR/mut-patterns.rs:42:21 | LL | let mut $p = 0; | ^^ expected identifier @@ -73,5 +97,5 @@ LL | let mut $p = 0; LL | foo!(x); | -------- in this macro invocation -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/src/test/ui/self/self_type_keyword.rs b/src/test/ui/self/self_type_keyword.rs index d479905932b..844f13c2f89 100644 --- a/src/test/ui/self/self_type_keyword.rs +++ b/src/test/ui/self/self_type_keyword.rs @@ -14,7 +14,7 @@ pub fn main() { ref Self => (), //~^ ERROR expected identifier, found keyword `Self` mut Self => (), - //~^ ERROR `mut` must be attached to each individual binding + //~^ ERROR `mut` must be followed by a named binding //~| ERROR cannot find unit struct/variant or constant `Self` ref mut Self => (), //~^ ERROR expected identifier, found keyword `Self` diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index fdae06ccdd9..bb631194bf3 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -10,11 +10,13 @@ error: expected identifier, found keyword `Self` LL | ref Self => (), | ^^^^ expected identifier, found keyword -error: `mut` must be attached to each individual binding +error: `mut` must be followed by a named binding --> $DIR/self_type_keyword.rs:16:9 | LL | mut Self => (), - | ^^^^^^^^ help: add `mut` to each binding: `Self` + | ^^^^^^^^ help: remove the `mut` prefix: `Self` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: expected identifier, found keyword `Self` --> $DIR/self_type_keyword.rs:19:17 -- cgit 1.4.1-3-g733a5 From 6f67bbc445e5c2b426abc4ac0db4c1dcffd48452 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 28 Aug 2019 02:23:58 +0200 Subject: or-pattern: fix typo in error message --- src/libsyntax/parse/parser/pat.rs | 2 +- src/test/ui/or-patterns/while-parsing-this-or-pattern.rs | 2 +- src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 78c9a289b37..4c6b6ce38f6 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -113,7 +113,7 @@ impl<'a> Parser<'a> { let mut pats = vec![first_pat]; while self.eat_or_separator() { let pat = self.parse_pat(expected).map_err(|mut err| { - err.span_label(lo, "while parsing this or-pattern staring here"); + err.span_label(lo, "while parsing this or-pattern starting here"); err })?; self.maybe_recover_unexpected_comma(pat.span, rc)?; diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs index 4a9fae1406a..b9bfb8638b2 100644 --- a/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs +++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs @@ -3,7 +3,7 @@ fn main() { match Some(42) { Some(42) | .=. => {} //~ ERROR expected pattern, found `.` - //~^ while parsing this or-pattern staring here + //~^ while parsing this or-pattern starting here //~| NOTE expected pattern } } diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr index 21fece6c64f..7ad62ff99ee 100644 --- a/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr +++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr @@ -4,7 +4,7 @@ error: expected pattern, found `.` LL | Some(42) | .=. => {} | -------- ^ expected pattern | | - | while parsing this or-pattern staring here + | while parsing this or-pattern starting here error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 26e9990198d3c7262d58468f18a722920c897e35 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 19 May 2019 20:16:04 +0200 Subject: Add a "diagnostic item" scheme This allows lints and other diagnostics to refer to items by a unique ID instead of relying on whacky path resolution schemes that may break when items are relocated. --- src/liballoc/vec.rs | 1 + src/libcore/fmt/mod.rs | 3 +- src/librustc/arena.rs | 4 + src/librustc/lib.rs | 2 + src/librustc/lint/internal.rs | 16 +-- src/librustc/middle/diagnostic_items.rs | 123 +++++++++++++++++++++ src/librustc/middle/lang_items.rs | 2 - src/librustc/query/mod.rs | 19 +++- src/librustc/ty/context.rs | 21 ++++ src/librustc/ty/mod.rs | 1 + src/librustc/ty/sty.rs | 1 + src/librustc_lint/builtin.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/decoder.rs | 18 +++ src/librustc_metadata/encoder.rs | 15 ++- src/librustc_metadata/schema.rs | 1 + src/libsyntax/feature_gate/builtin_attrs.rs | 11 ++ src/libsyntax_pos/symbol.rs | 5 +- src/test/ui/tool-attributes/diagnostic_item.rs | 2 + src/test/ui/tool-attributes/diagnostic_item.stderr | 17 +++ src/test/ui/tool-attributes/diagnostic_item2.rs | 6 + src/test/ui/tool-attributes/diagnostic_item3.rs | 7 ++ 22 files changed, 260 insertions(+), 18 deletions(-) create mode 100644 src/librustc/middle/diagnostic_items.rs create mode 100644 src/test/ui/tool-attributes/diagnostic_item.rs create mode 100644 src/test/ui/tool-attributes/diagnostic_item.stderr create mode 100644 src/test/ui/tool-attributes/diagnostic_item2.rs create mode 100644 src/test/ui/tool-attributes/diagnostic_item3.rs (limited to 'src/libsyntax') diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index d2798955c46..d5dc2d4b868 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -291,6 +291,7 @@ use crate::raw_vec::RawVec; /// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve /// [owned slice]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(all(not(bootstrap), not(test)), rustc_diagnostic_item = "vec_type")] pub struct Vec { buf: RawVec, len: usize, diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index bd31d25dd03..7e35188bc10 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -518,7 +518,8 @@ impl Display for Arguments<'_> { label="`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`", )] #[doc(alias = "{:?}")] -#[lang = "debug_trait"] +#[cfg_attr(boostrap_stdarch_ignore_this, lang = "debug_trait")] +#[cfg_attr(not(boostrap_stdarch_ignore_this), rustc_diagnostic_item = "debug_trait")] pub trait Debug { /// Formats the value using the given formatter. /// diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index a38dbbdd50c..b3a561ef74b 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -94,6 +94,10 @@ macro_rules! arena_types { rustc::hir::def_id::CrateNum > >, + [few] diagnostic_items: rustc_data_structures::fx::FxHashMap< + syntax::symbol::Symbol, + rustc::hir::def_id::DefId, + >, [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes, [decode] generic_predicates: rustc::ty::GenericPredicates<'tcx>, [few] lint_levels: rustc::lint::LintLevelMap, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8d4cd51e460..368f5bb64fe 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -62,6 +62,7 @@ #![feature(log_syntax)] #![feature(mem_take)] #![feature(associated_type_bounds)] +#![feature(rustc_attrs)] #![recursion_limit="512"] @@ -109,6 +110,7 @@ pub mod middle { pub mod cstore; pub mod dead; pub mod dependency_format; + pub mod diagnostic_items; pub mod entry; pub mod exported_symbols; pub mod free_region; diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index be73b305e2c..13834eaf40f 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -159,29 +159,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind { } fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment) -> bool { - if segment.ident.name == sym::TyKind { - if let Some(res) = segment.res { - if let Some(did) = res.opt_def_id() { - return cx.match_def_path(did, TYKIND_PATH); - } + if let Some(res) = segment.res { + if let Some(did) = res.opt_def_id() { + return cx.tcx.is_diagnostic_item(sym::TyKind, did); } } false } -const TYKIND_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::sty, sym::TyKind]; -const TY_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::Ty]; -const TYCTXT_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::context, sym::TyCtxt]; - fn is_ty_or_ty_ctxt(cx: &LateContext<'_, '_>, ty: &Ty) -> Option { match &ty.node { TyKind::Path(qpath) => { if let QPath::Resolved(_, path) = qpath { let did = path.res.opt_def_id()?; - if cx.match_def_path(did, TY_PATH) { + if cx.tcx.is_diagnostic_item(sym::Ty, did) { return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.match_def_path(did, TYCTXT_PATH) { + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); } } diff --git a/src/librustc/middle/diagnostic_items.rs b/src/librustc/middle/diagnostic_items.rs new file mode 100644 index 00000000000..dfae169b278 --- /dev/null +++ b/src/librustc/middle/diagnostic_items.rs @@ -0,0 +1,123 @@ +//! Detecting diagnostic items. +//! +//! Diagnostic items are items that are not language-inherent, but can reasonably be expected to +//! exist for diagnostic purposes. This allows diagnostic authors to refer to specific items +//! directly, without having to guess module paths and crates. +//! Examples are: +//! +//! * Traits like `Debug`, that have no bearing on language semantics +//! +//! * Compiler internal types like `Ty` and `TyCtxt` + +use crate::hir::def_id::{DefId, LOCAL_CRATE}; +use crate::ty::TyCtxt; +use crate::util::nodemap::FxHashMap; + +use syntax::ast; +use syntax::symbol::{Symbol, sym}; +use crate::hir::itemlikevisit::ItemLikeVisitor; +use crate::hir; + +struct DiagnosticItemCollector<'tcx> { + // items from this crate + items: FxHashMap, + tcx: TyCtxt<'tcx>, +} + +impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + self.observe_item(&item.attrs, item.hir_id); + } + + fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + self.observe_item(&trait_item.attrs, trait_item.hir_id); + } + + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + self.observe_item(&impl_item.attrs, impl_item.hir_id); + } +} + +impl<'tcx> DiagnosticItemCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> { + DiagnosticItemCollector { + tcx, + items: Default::default(), + } + } + + fn observe_item(&mut self, attrs: &[ast::Attribute], hir_id: hir::HirId) { + if let Some(name) = extract(attrs) { + let def_id = self.tcx.hir().local_def_id(hir_id); + // insert into our table + collect_item(self.tcx, &mut self.items, name, def_id); + } + } +} + +fn collect_item( + tcx: TyCtxt<'_>, + items: &mut FxHashMap, + name: Symbol, + item_def_id: DefId, +) { + // Check for duplicates. + if let Some(original_def_id) = items.insert(name, item_def_id) { + if original_def_id != item_def_id { + let mut err = match tcx.hir().span_if_local(item_def_id) { + Some(span) => tcx.sess.struct_span_err( + span, + &format!("duplicate diagnostic item found: `{}`.", name)), + None => tcx.sess.struct_err(&format!( + "duplicate diagnostic item in crate `{}`: `{}`.", + tcx.crate_name(item_def_id.krate), + name)), + }; + if let Some(span) = tcx.hir().span_if_local(original_def_id) { + span_note!(&mut err, span, "first defined here."); + } else { + err.note(&format!("first defined in crate `{}`.", + tcx.crate_name(original_def_id.krate))); + } + err.emit(); + } + } +} + +/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes. +fn extract(attrs: &[ast::Attribute]) -> Option { + attrs.iter().find_map(|attr| { + if attr.check_name(sym::rustc_diagnostic_item) { + attr.value_str() + } else { + None + } + }) +} + +/// Traverse and collect the diagnostic items in the current +pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx FxHashMap { + // Initialize the collector. + let mut collector = DiagnosticItemCollector::new(tcx); + + // Collect diagnostic items in this crate. + tcx.hir().krate().visit_all_item_likes(&mut collector); + + tcx.arena.alloc(collector.items) +} + + +/// Traverse and collect all the diagnostic items in all crates. +pub fn collect_all<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx FxHashMap { + // Initialize the collector. + let mut collector = FxHashMap::default(); + + // Collect diagnostic items in other crates. + for &cnum in tcx.crates().iter().chain(std::iter::once(&LOCAL_CRATE)) { + for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() { + collect_item(tcx, &mut collector, name, def_id); + } + } + + tcx.arena.alloc(collector) +} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 334c06618bb..6b04600eb75 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -367,8 +367,6 @@ language_item_table! { MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union; - DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait; - // Align offset for stride != 1, must not panic. AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index c4f7ca51f4a..ef838114f6c 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -804,7 +804,7 @@ rustc_queries! { } BorrowChecking { - // Lifetime resolution. See `middle::resolve_lifetimes`. + /// Lifetime resolution. See `middle::resolve_lifetimes`. query resolve_lifetimes(_: CrateNum) -> &'tcx ResolveLifetimes { desc { "resolving lifetimes" } } @@ -846,13 +846,30 @@ rustc_queries! { -> &'tcx [(Symbol, Option)] { desc { "calculating the lib features defined in a crate" } } + /// Returns the lang items defined in another crate by loading it from metadata. + // FIXME: It is illegal to pass a `CrateNum` other than `LOCAL_CRATE` here, just get rid + // of that argument? query get_lang_items(_: CrateNum) -> &'tcx LanguageItems { eval_always desc { "calculating the lang items map" } } + + /// Returns all diagnostic items defined in all crates + query all_diagnostic_items(_: CrateNum) -> &'tcx FxHashMap { + eval_always + desc { "calculating the diagnostic items map" } + } + + /// Returns the lang items defined in another crate by loading it from metadata. query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] { desc { "calculating the lang items defined in a crate" } } + + /// Returns the diagnostic items defined in a crate + query diagnostic_items(_: CrateNum) -> &'tcx FxHashMap { + desc { "calculating the diagnostic items map in a crate" } + } + query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] { desc { "calculating the missing lang items in a crate" } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index c0d86a79882..e240e0df8b9 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -978,6 +978,7 @@ pub struct FreeRegionInfo { /// /// [rustc guide]: https://rust-lang.github.io/rustc-guide/ty.html #[derive(Copy, Clone)] +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "TyCtxt")] pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } @@ -1308,10 +1309,22 @@ impl<'tcx> TyCtxt<'tcx> { self.get_lib_features(LOCAL_CRATE) } + /// Obtain all lang items of this crate and all dependencies (recursively) pub fn lang_items(self) -> &'tcx middle::lang_items::LanguageItems { self.get_lang_items(LOCAL_CRATE) } + /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to + /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. + pub fn get_diagnostic_item(self, name: Symbol) -> Option { + self.all_diagnostic_items(LOCAL_CRATE).get(&name).copied() + } + + /// Check whether the diagnostic item with the given `name` has the given `DefId`. + pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool { + self.diagnostic_items(did.krate).get(&name) == Some(&did) + } + pub fn stability(self) -> &'tcx stability::Index<'tcx> { self.stability_index(LOCAL_CRATE) } @@ -2896,6 +2909,14 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { assert_eq!(id, LOCAL_CRATE); tcx.arena.alloc(middle::lang_items::collect(tcx)) }; + providers.diagnostic_items = |tcx, id| { + assert_eq!(id, LOCAL_CRATE); + middle::diagnostic_items::collect(tcx) + }; + providers.all_diagnostic_items = |tcx, id| { + assert_eq!(id, LOCAL_CRATE); + middle::diagnostic_items::collect_all(tcx) + }; providers.maybe_unused_trait_import = |tcx, id| { tcx.maybe_unused_trait_imports.contains(&id) }; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index eaaaf75f75d..56505c04f0f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -581,6 +581,7 @@ impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { } } +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "Ty")] pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> rustc_serialize::UseSpecializedEncodable for Ty<'tcx> {} diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index f41fffe507d..d2edf6fb1ee 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -86,6 +86,7 @@ impl BoundRegion { /// AST structure in `libsyntax/ast.rs` as well. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, Debug)] +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "TyKind")] pub enum TyKind<'tcx> { /// The primitive boolean type. Written as `bool`. Bool, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d3c94060e27..26e7b789f8f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -570,7 +570,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { _ => return, } - let debug = match cx.tcx.lang_items().debug_trait() { + let debug = match cx.tcx.get_diagnostic_item(sym::debug_trait) { Some(debug) => debug, None => return, }; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index ca0cf0a5a66..d6450f00c8b 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -226,6 +226,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, } defined_lib_features => { cdata.get_lib_features(tcx) } defined_lang_items => { cdata.get_lang_items(tcx) } + diagnostic_items => { cdata.get_diagnostic_items(tcx) } missing_lang_items => { cdata.get_missing_lang_items(tcx) } missing_extern_crate_item => { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index cdee14d07fb..75d72617047 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -12,6 +12,7 @@ use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxHashMap; use rustc::middle::lang_items; use rustc::mir::{self, interpret}; use rustc::mir::interpret::AllocDecodingSession; @@ -757,6 +758,23 @@ impl<'a, 'tcx> CrateMetadata { } } + /// Iterates over the diagnostic items in the given crate. + pub fn get_diagnostic_items( + &self, + tcx: TyCtxt<'tcx>, + ) -> &'tcx FxHashMap { + tcx.arena.alloc(if self.is_proc_macro_crate() { + // Proc macro crates do not export any diagnostic-items to the target. + Default::default() + } else { + self.root + .diagnostic_items + .decode(self) + .map(|(name, def_index)| (name, self.local_def_id(def_index))) + .collect() + }) + } + /// Iterates over each child of the given item. pub fn each_child_of_item(&self, id: DefIndex, mut callback: F, sess: &Session) where F: FnMut(def::Export) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0eafcebefd7..db212408d8e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -33,7 +33,7 @@ use syntax::ast; use syntax::attr; use syntax::ext::proc_macro::is_proc_macro_attr; use syntax::source_map::Spanned; -use syntax::symbol::{kw, sym, Ident}; +use syntax::symbol::{kw, sym, Ident, Symbol}; use syntax_pos::{self, FileName, SourceFile, Span}; use log::{debug, trace}; @@ -404,6 +404,11 @@ impl<'tcx> EncodeContext<'tcx> { let lang_items_missing = self.encode_lang_items_missing(); let lang_item_bytes = self.position() - i; + // Encode the diagnostic items. + i = self.position(); + let diagnostic_items = self.encode_diagnostic_items(); + let diagnostic_item_bytes = self.position() - i; + // Encode the native libraries used i = self.position(); let native_libraries = self.encode_native_libraries(); @@ -520,6 +525,7 @@ impl<'tcx> EncodeContext<'tcx> { dylib_dependency_formats, lib_features, lang_items, + diagnostic_items, lang_items_missing, native_libraries, foreign_modules, @@ -545,6 +551,7 @@ impl<'tcx> EncodeContext<'tcx> { println!(" dep bytes: {}", dep_bytes); println!(" lib feature bytes: {}", lib_feature_bytes); println!(" lang item bytes: {}", lang_item_bytes); + println!(" diagnostic item bytes: {}", diagnostic_item_bytes); println!(" native bytes: {}", native_lib_bytes); println!(" source_map bytes: {}", source_map_bytes); println!(" impl bytes: {}", impl_bytes); @@ -1555,6 +1562,12 @@ impl EncodeContext<'tcx> { self.lazy(lib_features.to_vec()) } + fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { + let tcx = self.tcx; + let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE); + self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) + } + fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> { let tcx = self.tcx; let lang_items = tcx.lang_items(); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 1a5887bbf4e..1a5f0e17ba7 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -176,6 +176,7 @@ pub struct CrateRoot<'tcx> { pub lib_features: Lazy<[(Symbol, Option)]>, pub lang_items: Lazy<[(DefIndex, usize)]>, pub lang_items_missing: Lazy<[lang_items::LangItem]>, + pub diagnostic_items: Lazy<[(Symbol, DefIndex)]>, pub native_libraries: Lazy<[NativeLibrary]>, pub foreign_modules: Lazy<[ForeignModule]>, pub source_map: Lazy<[syntax_pos::SourceFile]>, diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index b934f2e7f64..ee7ac3b15d9 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -461,6 +461,17 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ lang, Normal, template!(NameValueStr: "name"), lang_items, "language items are subject to change", ), + ( + sym::rustc_diagnostic_item, + Normal, + template!(NameValueStr: "name"), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "diagnostic items compiler internal support for linting", + cfg_fn!(rustc_attrs), + ), + ), ( sym::no_debug, Whitelisted, template!(Word), Gated( diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 8833e03c72b..f44716e013e 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -225,9 +225,10 @@ symbols! { custom_inner_attributes, custom_test_frameworks, c_variadic, - Debug, + debug_trait, declare_lint_pass, decl_macro, + Debug, Decodable, Default, default_lib_allocator, @@ -238,6 +239,7 @@ symbols! { deref, deref_mut, derive, + diagnostic, direct, doc, doc_alias, @@ -569,6 +571,7 @@ symbols! { rustc_conversion_suggestion, rustc_def_path, rustc_deprecated, + rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, rustc_dummy, diff --git a/src/test/ui/tool-attributes/diagnostic_item.rs b/src/test/ui/tool-attributes/diagnostic_item.rs new file mode 100644 index 00000000000..88157bbbf61 --- /dev/null +++ b/src/test/ui/tool-attributes/diagnostic_item.rs @@ -0,0 +1,2 @@ +#[rustc_diagnostic_item = "foomp"] //~ ERROR will never be stabilized +struct Foomp; diff --git a/src/test/ui/tool-attributes/diagnostic_item.stderr b/src/test/ui/tool-attributes/diagnostic_item.stderr new file mode 100644 index 00000000000..4472914118b --- /dev/null +++ b/src/test/ui/tool-attributes/diagnostic_item.stderr @@ -0,0 +1,17 @@ +error[E0658]: diagnostic items compiler are internal support for linting and will never be stabilized + --> $DIR/diagnostic_item.rs:1:1 + | +LL | #[rustc_diagnostic_item = "foomp"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + +error[E0601]: `main` function not found in crate `diagnostic_item` + | + = note: consider adding a `main` function to `$DIR/diagnostic_item.rs` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0601, E0658. +For more information about an error, try `rustc --explain E0601`. diff --git a/src/test/ui/tool-attributes/diagnostic_item2.rs b/src/test/ui/tool-attributes/diagnostic_item2.rs new file mode 100644 index 00000000000..b32a66b16be --- /dev/null +++ b/src/test/ui/tool-attributes/diagnostic_item2.rs @@ -0,0 +1,6 @@ +// check-pass + +#[clippy::diagnostic_item = "mep"] +struct Mep; + +fn main() {} diff --git a/src/test/ui/tool-attributes/diagnostic_item3.rs b/src/test/ui/tool-attributes/diagnostic_item3.rs new file mode 100644 index 00000000000..c1a236ed1cc --- /dev/null +++ b/src/test/ui/tool-attributes/diagnostic_item3.rs @@ -0,0 +1,7 @@ +// check-pass +#![feature(rustc_attrs)] + +#[rustc_diagnostic_item = "foomp"] +struct Foomp; + +fn main() {} -- cgit 1.4.1-3-g733a5