diff --git a/Cargo.lock b/Cargo.lock index 93845578293..6aee143feab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3512,7 +3512,6 @@ dependencies = [ "rustc_span", "rustc_target", "thin-vec", - "tracing", ] [[package]] diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index c1ebfb3e6d0..0001394c8d3 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -19,5 +19,4 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } thin-vec = "0.2.12" -tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 477d3732d46..3d0513c8923 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1442,62 +1442,54 @@ fn deny_equality_constraints( let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None }; // Given `::Bar = RhsTy`, suggest `A: Foo`. - if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind { - if let TyKind::Path(None, path) = &qself.ty.kind { - match &path.segments[..] { - [PathSegment { ident, args: None, .. }] => { - for param in &generics.params { - if param.ident == *ident { - let param = ident; - match &full_path.segments[qself.position..] { - [PathSegment { ident, args, .. }] => { - // Make a new `Path` from `foo::Bar` to `Foo`. - let mut assoc_path = full_path.clone(); - // Remove `Bar` from `Foo::Bar`. - assoc_path.segments.pop(); - let len = assoc_path.segments.len() - 1; - let gen_args = args.as_deref().cloned(); - // Build ``. - let arg = AngleBracketedArg::Constraint(AssocConstraint { - id: rustc_ast::node_id::DUMMY_NODE_ID, - ident: *ident, - gen_args, - kind: AssocConstraintKind::Equality { - term: predicate.rhs_ty.clone().into(), - }, - span: ident.span, - }); - // Add `` to `Foo`. - match &mut assoc_path.segments[len].args { - Some(args) => match args.deref_mut() { - GenericArgs::Parenthesized(_) => continue, - GenericArgs::AngleBracketed(args) => { - args.args.push(arg); - } - }, - empty_args => { - *empty_args = Some( - AngleBracketedArgs { - span: ident.span, - args: thin_vec![arg], - } - .into(), - ); - } - } - err.assoc = Some(errors::AssociatedSuggestion { - span: predicate.span, - ident: *ident, - param: *param, - path: pprust::path_to_string(&assoc_path), - }) - } - _ => {} - }; + if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind + && let TyKind::Path(None, path) = &qself.ty.kind + && let [PathSegment { ident, args: None, .. }] = &path.segments[..] + { + for param in &generics.params { + if param.ident == *ident + && let [PathSegment { ident, args, .. }] = &full_path.segments[qself.position..] + { + // Make a new `Path` from `foo::Bar` to `Foo`. + let mut assoc_path = full_path.clone(); + // Remove `Bar` from `Foo::Bar`. + assoc_path.segments.pop(); + let len = assoc_path.segments.len() - 1; + let gen_args = args.as_deref().cloned(); + // Build ``. + let arg = AngleBracketedArg::Constraint(AssocConstraint { + id: rustc_ast::node_id::DUMMY_NODE_ID, + ident: *ident, + gen_args, + kind: AssocConstraintKind::Equality { + term: predicate.rhs_ty.clone().into(), + }, + span: ident.span, + }); + // Add `` to `Foo`. + match &mut assoc_path.segments[len].args { + Some(args) => match args.deref_mut() { + GenericArgs::Parenthesized(_) => continue, + GenericArgs::AngleBracketed(args) => { + args.args.push(arg); } + }, + empty_args => { + *empty_args = Some( + AngleBracketedArgs { + span: ident.span, + args: thin_vec![arg], + } + .into(), + ); } } - _ => {} + err.assoc = Some(errors::AssociatedSuggestion { + span: predicate.span, + ident: *ident, + param: param.ident, + path: pprust::path_to_string(&assoc_path), + }) } } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index a1bd2679137..e1cf0a2589d 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -10,53 +10,54 @@ use rustc_span::Span; use rustc_target::spec::abi; use thin_vec::ThinVec; -use tracing::debug; use crate::errors; -macro_rules! gate_feature_fn { - ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{ - let (visitor, has_feature, span, name, explain, help) = - (&*$visitor, $has_feature, $span, $name, $explain, $help); - let has_feature: bool = has_feature(visitor.features); - debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !span.allows_unstable($name) { - feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit(); +/// The common case. +macro_rules! gate { + ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ + if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain).emit(); } }}; - ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ - let (visitor, has_feature, span, name, explain) = - (&*$visitor, $has_feature, $span, $name, $explain); - let has_feature: bool = has_feature(visitor.features); - debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !span.allows_unstable($name) { - feature_err(&visitor.sess.parse_sess, name, span, explain).emit(); - } - }}; - (future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ - let (visitor, has_feature, span, name, explain) = - (&*$visitor, $has_feature, $span, $name, $explain); - let has_feature: bool = has_feature(visitor.features); - debug!( - "gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)", - name, span, has_feature - ); - if !has_feature && !span.allows_unstable($name) { - feature_warn(&visitor.sess.parse_sess, name, span, explain); + ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ + if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain) + .help($help) + .emit(); } }}; } -macro_rules! gate_feature_post { - ($visitor: expr, $feature: ident, $span: expr, $explain: expr, $help: expr) => { - gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain, $help) - }; - ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => { - gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) - }; - (future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => { - gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) - }; +/// The unusual case, where the `has_feature` condition is non-standard. +macro_rules! gate_alt { + ($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{ + if !$has_feature && !$span.allows_unstable($name) { + feature_err(&$visitor.sess.parse_sess, $name, $span, $explain).emit(); + } + }}; +} + +/// The case involving a multispan. +macro_rules! gate_multi { + ($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{ + if !$visitor.features.$feature { + let spans: Vec<_> = + $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect(); + if !spans.is_empty() { + feature_err(&$visitor.sess.parse_sess, sym::$feature, spans, $explain).emit(); + } + } + }}; +} + +/// The legacy case. +macro_rules! gate_legacy { + ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ + if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + feature_warn(&$visitor.sess.parse_sess, sym::$feature, $span, $explain); + } + }}; } pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) { @@ -78,7 +79,7 @@ fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) { match symbol_unescaped { // Stable sym::Rust | sym::C => {} - abi => gate_feature_post!( + abi => gate!( &self, const_extern_fn, span, @@ -129,14 +130,14 @@ impl Visitor<'_> for ImplTraitVisitor<'_> { fn visit_ty(&mut self, ty: &ast::Ty) { if let ast::TyKind::ImplTrait(..) = ty.kind { if self.in_associated_ty { - gate_feature_post!( + gate!( &self.vis, impl_trait_in_assoc_type, ty.span, "`impl Trait` in associated types is unstable" ); } else { - gate_feature_post!( + gate!( &self.vis, type_alias_impl_trait, ty.span, @@ -153,23 +154,16 @@ fn visit_ty(&mut self, ty: &ast::Ty) { fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) { // Check only lifetime parameters are present and that the lifetime // parameters that are present have no bounds. - let non_lt_param_spans: Vec<_> = params - .iter() - .filter_map(|param| match param.kind { - ast::GenericParamKind::Lifetime { .. } => None, - _ => Some(param.ident.span), - }) - .collect(); - // FIXME: gate_feature_post doesn't really handle multispans... - if !non_lt_param_spans.is_empty() && !self.features.non_lifetime_binders { - feature_err( - &self.sess.parse_sess, - sym::non_lifetime_binders, - non_lt_param_spans, - crate::fluent_generated::ast_passes_forbidden_non_lifetime_param, - ) - .emit(); - } + let non_lt_param_spans = params.iter().filter_map(|param| match param.kind { + ast::GenericParamKind::Lifetime { .. } => None, + _ => Some(param.ident.span), + }); + gate_multi!( + &self, + non_lifetime_binders, + non_lt_param_spans, + crate::fluent_generated::ast_passes_forbidden_non_lifetime_param + ); for param in params { if !param.bounds.is_empty() { let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); @@ -188,48 +182,39 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) { .. }) = attr_info { - gate_feature_fn!(self, has_feature, attr.span, *name, *descr); + gate_alt!(self, has_feature(&self.features), *name, attr.span, *descr); } // Check unstable flavors of the `#[doc]` attribute. if attr.has_name(sym::doc) { for nested_meta in attr.meta_item_list().unwrap_or_default() { - macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => { - $(if nested_meta.has_name(sym::$name) { - let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental"); - gate_feature_post!(self, $feature, attr.span, msg); - })* + macro_rules! gate_doc { ($($s:literal { $($name:ident => $feature:ident)* })*) => { + $($(if nested_meta.has_name(sym::$name) { + let msg = concat!("`#[doc(", stringify!($name), ")]` is ", $s); + gate!(self, $feature, attr.span, msg); + })*)* }} gate_doc!( - cfg => doc_cfg - cfg_hide => doc_cfg_hide - masked => doc_masked - notable_trait => doc_notable_trait + "experimental" { + cfg => doc_cfg + cfg_hide => doc_cfg_hide + masked => doc_masked + notable_trait => doc_notable_trait + } + "meant for internal use only" { + keyword => rustdoc_internals + fake_variadic => rustdoc_internals + } ); - - if nested_meta.has_name(sym::keyword) { - let msg = "`#[doc(keyword)]` is meant for internal use only"; - gate_feature_post!(self, rustdoc_internals, attr.span, msg); - } - - if nested_meta.has_name(sym::fake_variadic) { - let msg = "`#[doc(fake_variadic)]` is meant for internal use only"; - gate_feature_post!(self, rustdoc_internals, attr.span, msg); - } } } if !attr.is_doc_comment() - && attr.get_normal_item().path.segments.len() == 2 - && attr.get_normal_item().path.segments[0].ident.name == sym::diagnostic + && let [seg, _] = attr.get_normal_item().path.segments.as_slice() + && seg.ident.name == sym::diagnostic && !self.features.diagnostic_namespace { let msg = "`#[diagnostic]` attribute name space is experimental"; - gate_feature_post!( - self, - diagnostic_namespace, - attr.get_normal_item().path.segments[0].ident.span, - msg - ); + gate!(self, diagnostic_namespace, seg.ident.span, msg); } // Emit errors for non-staged-api crates. @@ -255,12 +240,11 @@ fn visit_item(&mut self, i: &'a ast::Item) { ast::ItemKind::Fn(..) => { if attr::contains_name(&i.attrs, sym::start) { - gate_feature_post!( + gate!( &self, start, i.span, - "`#[start]` functions are experimental \ - and their signature may change \ + "`#[start]` functions are experimental and their signature may change \ over time" ); } @@ -270,7 +254,7 @@ fn visit_item(&mut self, i: &'a ast::Item) { for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(sym::simd) { - gate_feature_post!( + gate!( &self, repr_simd, attr.span, @@ -283,7 +267,7 @@ fn visit_item(&mut self, i: &'a ast::Item) { ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, of_trait, .. }) => { if let &ast::ImplPolarity::Negative(span) = polarity { - gate_feature_post!( + gate!( &self, negative_impls, span.to(of_trait.as_ref().map_or(span, |t| t.path.span)), @@ -293,12 +277,12 @@ fn visit_item(&mut self, i: &'a ast::Item) { } if let ast::Defaultness::Default(_) = defaultness { - gate_feature_post!(&self, specialization, i.span, "specialization is unstable"); + gate!(&self, specialization, i.span, "specialization is unstable"); } } ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => { - gate_feature_post!( + gate!( &self, auto_traits, i.span, @@ -307,12 +291,12 @@ fn visit_item(&mut self, i: &'a ast::Item) { } ast::ItemKind::TraitAlias(..) => { - gate_feature_post!(&self, trait_alias, i.span, "trait aliases are experimental"); + gate!(&self, trait_alias, i.span, "trait aliases are experimental"); } ast::ItemKind::MacroDef(ast::MacroDef { macro_rules: false, .. }) => { let msg = "`macro` is experimental"; - gate_feature_post!(&self, decl_macro, i.span, msg); + gate!(&self, decl_macro, i.span, msg); } ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => { @@ -331,7 +315,7 @@ fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); let links_to_llvm = link_name.is_some_and(|val| val.as_str().starts_with("llvm.")); if links_to_llvm { - gate_feature_post!( + gate!( &self, link_llvm_intrinsics, i.span, @@ -340,7 +324,7 @@ fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { } } ast::ForeignItemKind::TyAlias(..) => { - gate_feature_post!(&self, extern_types, i.span, "extern types are experimental"); + gate!(&self, extern_types, i.span, "extern types are experimental"); } ast::ForeignItemKind::MacCall(..) => {} } @@ -356,7 +340,7 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) { self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params); } ast::TyKind::Never => { - gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); + gate!(&self, never_type, ty.span, "the `!` type is experimental"); } _ => {} } @@ -389,7 +373,7 @@ fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) { fn visit_expr(&mut self, e: &'a ast::Expr) { match e.kind { ast::ExprKind::TryBlock(_) => { - gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); + gate!(&self, try_blocks, e.span, "`try` expression is experimental"); } _ => {} } @@ -405,7 +389,7 @@ fn visit_pat(&mut self, pattern: &'a ast::Pat) { _ => pat, }; if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind { - gate_feature_post!( + gate!( &self, half_open_range_patterns_in_slices, pat.span, @@ -415,15 +399,10 @@ fn visit_pat(&mut self, pattern: &'a ast::Pat) { } } PatKind::Box(..) => { - gate_feature_post!( - &self, - box_patterns, - pattern.span, - "box pattern syntax is experimental" - ); + gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); } PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => { - gate_feature_post!( + gate!( &self, exclusive_range_pattern, pattern.span, @@ -451,7 +430,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { } if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() { - gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); + gate!(&self, c_variadic, span, "C-variadic functions are unstable"); } visit::walk_fn(self, fn_kind) @@ -463,14 +442,14 @@ fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) { && args.inputs.is_empty() && matches!(args.output, ast::FnRetTy::Default(..)) { - gate_feature_post!( + gate!( &self, return_type_notation, constraint.span, "return type notation is experimental" ); } else { - gate_feature_post!( + gate!( &self, associated_type_bounds, constraint.span, @@ -486,7 +465,7 @@ fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { ast::AssocItemKind::Fn(_) => true, ast::AssocItemKind::Type(box ast::TyAlias { ty, .. }) => { if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { - gate_feature_post!( + gate!( &self, associated_type_defaults, i.span, @@ -502,11 +481,11 @@ fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { }; if let ast::Defaultness::Default(_) = i.kind.defaultness() { // Limit `min_specialization` to only specializing functions. - gate_feature_fn!( + gate_alt!( &self, - |x: &Features| x.specialization || (is_fn && x.min_specialization), - i.span, + self.features.specialization || (is_fn && self.features.min_specialization), sym::specialization, + i.span, "specialization is unstable" ); } @@ -521,17 +500,17 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { let spans = sess.parse_sess.gated_spans.spans.borrow(); macro_rules! gate_all { - ($gate:ident, $msg:literal, $help:literal) => { - if let Some(spans) = spans.get(&sym::$gate) { - for span in spans { - gate_feature_post!(&visitor, $gate, *span, $msg, $help); - } - } - }; ($gate:ident, $msg:literal) => { if let Some(spans) = spans.get(&sym::$gate) { for span in spans { - gate_feature_post!(&visitor, $gate, *span, $msg); + gate!(&visitor, $gate, *span, $msg); + } + } + }; + ($gate:ident, $msg:literal, $help:literal) => { + if let Some(spans) = spans.get(&sym::$gate) { + for span in spans { + gate!(&visitor, $gate, *span, $msg, $help); } } }; @@ -556,7 +535,7 @@ macro_rules! gate_all { gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); for &span in spans.get(&sym::yield_expr).iter().copied().flatten() { if !span.at_least_rust_2024() { - gate_feature_post!(&visitor, coroutines, span, "yield syntax is experimental"); + gate!(&visitor, coroutines, span, "yield syntax is experimental"); } } gate_all!(gen_blocks, "gen blocks are experimental"); @@ -590,7 +569,7 @@ macro_rules! gate_all { macro_rules! gate_all_legacy_dont_use { ($gate:ident, $msg:literal) => { for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { - gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg); + gate_legacy!(&visitor, $gate, *span, $msg); } }; } diff --git a/tests/ui/bounds-lifetime.rs b/tests/ui/bounds-lifetime.rs index 31aa4011b91..e3e635a4e84 100644 --- a/tests/ui/bounds-lifetime.rs +++ b/tests/ui/bounds-lifetime.rs @@ -2,6 +2,6 @@ type B = for<'b, 'a: 'b,> fn(); //~ ERROR lifetime bounds cannot be used in this context type C = for<'b, 'a: 'b +> fn(); //~ ERROR lifetime bounds cannot be used in this context type D = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context -type E = dyn for Fn(); //~ ERROR only lifetime parameters can be used in this context +type E = dyn for Fn(); //~ ERROR only lifetime parameters can be used in this context fn main() {} diff --git a/tests/ui/bounds-lifetime.stderr b/tests/ui/bounds-lifetime.stderr index f0bfe784ccc..bbae835d875 100644 --- a/tests/ui/bounds-lifetime.stderr +++ b/tests/ui/bounds-lifetime.stderr @@ -28,8 +28,8 @@ LL | type D = for<'a, T> fn(); error[E0658]: only lifetime parameters can be used in this context --> $DIR/bounds-lifetime.rs:5:18 | -LL | type E = dyn for Fn(); - | ^ +LL | type E = dyn for Fn(); + | ^ ^ | = note: see issue #108185 for more information = help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable