From 8226783a4c332a502c76354867a020506d64f5f2 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Fri, 23 Feb 2024 16:39:57 +0300 Subject: [PATCH] add polarity --- compiler/rustc_ast_lowering/src/lib.rs | 28 +++++++++---------- compiler/rustc_ast_passes/messages.ftl | 5 ---- .../rustc_ast_passes/src/ast_validation.rs | 10 +------ compiler/rustc_ast_passes/src/errors.rs | 16 ----------- compiler/rustc_ast_passes/src/feature_gate.rs | 21 ++++++++++++++ compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_hir/src/hir.rs | 6 +++- compiler/rustc_hir/src/intravisit.rs | 4 ++- .../rustc_hir_analysis/src/astconv/bounds.rs | 14 ++++++---- .../rustc_hir_analysis/src/astconv/errors.rs | 6 ++-- .../rustc_hir_analysis/src/astconv/lint.rs | 4 +-- .../src/astconv/object_safety.rs | 9 ++++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 5 +++- compiler/rustc_hir_pretty/src/lib.rs | 5 +++- .../nice_region_error/find_anon_type.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 2 +- .../src/traits/error_reporting/mod.rs | 2 +- compiler/rustc_lint/src/non_local_def.rs | 2 +- compiler/rustc_lint/src/traits.rs | 6 ++-- compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 4 +-- src/librustdoc/clean/mod.rs | 2 +- .../feature-gate-allow-maybe-polarity.rs | 13 +++++++++ .../feature-gate-allow-maybe-polarity.stderr | 27 ++++++++++++++++++ tests/ui/maybe-bounds.stderr | 16 ++++++++--- .../parser/trait-object-trait-parens.stderr | 18 +++++++++--- tests/ui/traits/maybe-polarity-pass.rs | 22 +++++++++++++++ tests/ui/traits/wf-object/maybe-bound.stderr | 26 +++++++++++++---- .../traits/wf-object/only-maybe-bound.stderr | 8 ++++-- 30 files changed, 200 insertions(+), 88 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-allow-maybe-polarity.rs create mode 100644 tests/ui/feature-gates/feature-gate-allow-maybe-polarity.stderr create mode 100644 tests/ui/traits/maybe-polarity-pass.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a5be91bb87209..30c4042478583 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1255,6 +1255,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx, TraitBoundModifiers::NONE, ); + let bound = (bound, hir::TraitBoundModifier::None); let bounds = this.arena.alloc_from_iter([bound]); let lifetime_bound = this.elided_dyn_bound(t.span); (bounds, lifetime_bound) @@ -1386,21 +1387,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We can safely ignore constness here since AST validation // takes care of rejecting invalid modifier combinations and // const trait bounds in trait object types. - GenericBound::Trait(ty, modifiers) => match modifiers.polarity { - BoundPolarity::Positive | BoundPolarity::Negative(_) => { - Some(this.lower_poly_trait_ref( - ty, - itctx, - // Still, don't pass along the constness here; we don't want to - // synthesize any host effect args, it'd only cause problems. - TraitBoundModifiers { - constness: BoundConstness::Never, - ..*modifiers - }, - )) - } - BoundPolarity::Maybe(_) => None, - }, + GenericBound::Trait(ty, modifiers) => { + // Still, don't pass along the constness here; we don't want to + // synthesize any host effect args, it'd only cause problems. + let modifiers = TraitBoundModifiers { + constness: BoundConstness::Never, + ..*modifiers + }; + let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers); + let polarity = this.lower_trait_bound_modifiers(modifiers); + Some((trait_ref, polarity)) + } GenericBound::Outlives(lifetime) => { if lifetime_bound.is_none() { lifetime_bound = Some(this.lower_lifetime(lifetime)); @@ -2502,6 +2499,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, span: self.lower_span(span), }; + let principal = (principal, hir::TraitBoundModifier::None); // The original ID is taken by the `PolyTraitRef`, // so the `Ty` itself needs a different one. diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 6586ca5d36f88..e2004d7ef50b2 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -202,11 +202,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax .help = use `auto trait Trait {"{}"}` instead -ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types - -ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits - .note = traits are `?{$path_str}` by default - ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters .suggestion = reorder the parameters: lifetimes, then consts and types diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 8c9ad83608761..6508fa10297d6 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1260,16 +1260,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { if let GenericBound::Trait(poly, modifiers) = bound { + // Some of the arms are feature-gated. See `feature_gate::PostExpansionVisitor`. match (ctxt, modifiers.constness, modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitSupertrait { - span: poly.span, - path_str: pprust::path_to_string(&poly.trait_ref.path), - }); - } - (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span }); - } (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => { self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span }); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index e5153c8979039..09d7fa893d1f2 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -543,22 +543,6 @@ pub struct NestedLifetimes { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_passes_optional_trait_supertrait)] -#[note] -pub struct OptionalTraitSupertrait { - #[primary_span] - pub span: Span, - pub path_str: String, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_optional_trait_object)] -pub struct OptionalTraitObject { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_const_bound_trait_object)] pub struct ConstBoundTraitObject { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1b0dd9acc3782..1c04d685d9e81 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -169,6 +169,27 @@ impl<'a> PostExpansionVisitor<'a> { } impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { + fn visit_param_bound(&mut self, bound: &'a ast::GenericBound, ctxt: visit::BoundKind) { + use ast::visit::BoundKind; + use ast::{BoundConstness, BoundPolarity}; + if let ast::GenericBound::Trait(poly, modifiers) = bound { + let gate = |descr| { + gate!(&self, allow_maybe_polarity, poly.span, descr); + }; + + match (ctxt, modifiers.constness, modifiers.polarity) { + (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { + gate("`?Trait` is not permitted in trait object types"); + } + (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { + gate("`?Trait` is not permitted in supertraits"); + } + _ => {} + } + } + visit::walk_param_bound(self, bound); + } + fn visit_attribute(&mut self, attr: &ast::Attribute) { let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); // Check feature gates for built-in attributes. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 53254d567ccf2..66ebebfcf5b7d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -191,6 +191,8 @@ declare_features! ( /// below (it has to be checked before expansion possibly makes /// macros disappear). (internal, allow_internal_unstable, "1.0.0", None), + /// Allows using `?Trait` trait bound. + (internal, allow_maybe_polarity, "CURRENT_RUSTC_VERSION", None), /// Allows using anonymous lifetimes in argument-position impl-trait. (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None), /// Allows identifying the `compiler_builtins` crate. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 78e7c636a3e74..436b298a2352b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2603,7 +2603,11 @@ pub enum TyKind<'hir> { OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), + TraitObject( + &'hir [(PolyTraitRef<'hir>, TraitBoundModifier)], + &'hir Lifetime, + TraitObjectSyntax, + ), /// Unused for now. Typeof(AnonConst), /// `TyKind::Infer` means the type should be inferred instead of it having been diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1c38a45d3a32f..4063a9d2682a5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -873,7 +873,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul try_visit!(visitor.visit_array_length(length)); } TyKind::TraitObject(bounds, ref lifetime, _syntax) => { - walk_list!(visitor, visit_poly_trait_ref, bounds); + for (bound, _) in bounds { + try_visit!(visitor.visit_poly_trait_ref(bound)); + } try_visit!(visitor.visit_lifetime(lifetime)); } TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)), diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 6d8a5bc0e9008..ad08bc1af25af 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -66,7 +66,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } } - if unbounds.len() > 1 { + if unbounds.len() > 1 && !tcx.features().allow_maybe_polarity { tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { spans: unbounds.iter().map(|ptr| ptr.span).collect(), }); @@ -80,12 +80,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { seen_sized_unbound = true; continue; } - // There was a `?Trait` bound, but it was not `?Sized`; warn. - tcx.dcx().span_warn( - unbound.span, - "relaxing a default bound only does something for `?Sized`; \ + if !tcx.features().allow_maybe_polarity { + // There was a `?Trait` bound, but it was not `?Sized`; warn. + tcx.dcx().span_warn( + unbound.span, + "relaxing a default bound only does something for `?Sized`; \ all other traits are not bound by default", - ); + ); + } } if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound { diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 214d960296880..b2a76bafe0bb2 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -592,7 +592,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, associated_types: FxIndexMap>, potential_assoc_types: Vec, - trait_bounds: &[hir::PolyTraitRef<'_>], + trait_bounds: &[(hir::PolyTraitRef<'_>, hir::TraitBoundModifier)], ) { if associated_types.values().all(|v| v.is_empty()) { return; @@ -634,7 +634,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if object_safety_violations { return; } - if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { + if let ([], [(bound, _)]) = (&potential_assoc_types[..], &trait_bounds) { match bound.trait_ref.path.segments { // FIXME: `trait_ref.path.span` can point to a full path with multiple // segments, even though `trait_ref.path.segments` is of length `1`. Work @@ -676,7 +676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // and we can then use their span to indicate this to the user. let bound_names = trait_bounds .iter() - .filter_map(|poly_trait_ref| { + .filter_map(|(poly_trait_ref, _)| { let path = poly_trait_ref.trait_ref.path.segments.last()?; let args = path.args?; diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index cee29b152e85a..bed8527de94b6 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -101,7 +101,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut is_downgradable = true; let is_object_safe = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { - objects.iter().all(|o| match o.trait_ref.path.res { + objects.iter().all(|(o, _)| match o.trait_ref.path.res { Res::Def(DefKind::Trait, id) => { if Some(id) == owner { // For recursive traits, don't downgrade the error. (#119652) @@ -192,7 +192,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { let tcx = self.tcx(); - if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = + if let hir::TyKind::TraitObject([(poly_trait_ref, _), ..], _, TraitObjectSyntax::None) = self_ty.kind { let needs_bracket = in_path diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 7705445ffaa42..b0e11f8fbbce8 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -22,7 +22,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, span: Span, hir_id: hir::HirId, - hir_trait_bounds: &[hir::PolyTraitRef<'tcx>], + hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)], lifetime: &hir::Lifetime, borrowed: bool, representation: DynKind, @@ -32,7 +32,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut bounds = Bounds::default(); let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in hir_trait_bounds.iter().rev() { + for (trait_bound, modifier) in hir_trait_bounds.iter().rev() { + if *modifier == hir::TraitBoundModifier::Maybe { + continue; + } if let GenericArgCountResult { correct: Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), @@ -279,7 +282,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let args = tcx.mk_args(&args); let span = i.bottom().1; - let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { + let empty_generic_args = hir_trait_bounds.iter().any(|(hir_bound, _)| { hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) && hir_bound.span.contains(span) }); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f03d0f8a88529..56cf0e649e72e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -834,7 +834,7 @@ impl<'tcx> TypeVisitor> for GATArgsCollector<'tcx> { fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { match ty.kind { - hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments { + hir::TyKind::TraitObject([(trait_ref, _)], ..) => match trait_ref.trait_ref.path.segments { [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), _ => false, }, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 22beac14b24db..5498f90087441 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -638,7 +638,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { debug!(?bounds, ?lifetime, "TraitObject"); let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { - for bound in bounds { + for (bound, modifier) in bounds { + if *modifier == hir::TraitBoundModifier::Maybe { + continue; + } this.visit_poly_trait_ref_inner( bound, NonLifetimeBinderAllowed::Deny("trait object types"), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 8f8f747339b42..5d1484254951c 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -293,13 +293,16 @@ impl<'a> State<'a> { self.word_space("dyn"); } let mut first = true; - for bound in bounds { + for (bound, modifier) in bounds { if first { first = false; } else { self.nbsp(); self.word_space("+"); } + if *modifier == TraitBoundModifier::Maybe { + self.word("?"); + } self.print_poly_trait_ref(bound); } if !lifetime.is_elided() { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index 4f74365d06c47..60ca178c938d0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -88,7 +88,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { } hir::TyKind::TraitObject(bounds, ..) => { - for bound in bounds { + for (bound, _) in bounds { self.current_index.shift_in(1); self.visit_poly_trait_ref(bound); self.current_index.shift_out(1); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 83e0b763d2448..ff4852e227eef 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { _, ) = t.kind { - for ptr in poly_trait_refs { + for (ptr, _) in poly_trait_refs { if Some(self.1) == ptr.trait_ref.trait_def_id() { self.0.push(ptr.span); } diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 0253f5a2df2a2..42d2101b1b52c 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -62,7 +62,7 @@ pub fn report_object_safety_error<'tcx>( if let Some(hir_id) = hir_id && let hir::Node::Ty(ty) = tcx.hir_node(hir_id) - && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind + && let hir::TyKind::TraitObject([(trait_ref, _), ..], ..) = ty.kind { let mut hir_id = hir_id; while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) { diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 6cb6fd1cbd550..40d99d8c52add 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -127,7 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { TyKind::Path(QPath::Resolved(_, ty_path)) => { path_has_local_parent(ty_path, cx, &*local_parents) } - TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => { + TyKind::TraitObject([(principle_poly_trait_ref, _), ..], _, _) => { path_has_local_parent( principle_poly_trait_ref.trait_ref.path, cx, diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 789f154eac5bc..44b449a59bf56 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -112,9 +112,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; - for bound in &bounds[..] { + for (bound, modifier) in &bounds[..] { let def_id = bound.trait_ref.trait_def_id(); - if cx.tcx.lang_items().drop_trait() == def_id { + if cx.tcx.lang_items().drop_trait() == def_id + && *modifier != hir::TraitBoundModifier::Maybe + { let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d472c406c4717..7047cedef9121 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -377,6 +377,7 @@ symbols! { allow_fail, allow_internal_unsafe, allow_internal_unstable, + allow_maybe_polarity, alu32, always, and, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 85f6da0d6cc82..ac4b64e9b5fea 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2994,11 +2994,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match ty.kind { hir::TyKind::TraitObject(traits, _, _) => { let (span, kw) = match traits { - [first, ..] if first.span.lo() == ty.span.lo() => { + [(first, _), ..] if first.span.lo() == ty.span.lo() => { // Missing `dyn` in front of trait object. (ty.span.shrink_to_lo(), "dyn ") } - [first, ..] => (ty.span.until(first.span), ""), + [(first, _), ..] => (ty.span.until(first.span), ""), [] => span_bug!(ty.span, "trait object with no traits: {ty:?}"), }; let needs_parens = traits.len() != 1; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b32d3ad562d03..e333c6aa29ae1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1859,7 +1859,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T } TyKind::Path(_) => clean_qpath(ty, cx), TyKind::TraitObject(bounds, ref lifetime, _) => { - let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect(); + let bounds = bounds.iter().map(|(bound, _)| clean_poly_trait_ref(bound, cx)).collect(); let lifetime = if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None }; DynTrait(bounds, lifetime) diff --git a/tests/ui/feature-gates/feature-gate-allow-maybe-polarity.rs b/tests/ui/feature-gates/feature-gate-allow-maybe-polarity.rs new file mode 100644 index 0000000000000..6cc30f182f00d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-allow-maybe-polarity.rs @@ -0,0 +1,13 @@ +#![feature(auto_traits)] + +trait Trait1 {} +auto trait Trait2 {} +trait Trait3: ?Trait1 {} +//~^ ERROR `?Trait` is not permitted in supertraits + +fn foo(_: Box) {} +//~^ ERROR `?Trait` is not permitted in trait object types +fn bar(_: T) {} +//~^ WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-allow-maybe-polarity.stderr b/tests/ui/feature-gates/feature-gate-allow-maybe-polarity.stderr new file mode 100644 index 0000000000000..f58ae2c0b1dc1 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-allow-maybe-polarity.stderr @@ -0,0 +1,27 @@ +error[E0658]: `?Trait` is not permitted in supertraits + --> $DIR/feature-gate-allow-maybe-polarity.rs:5:15 + | +LL | trait Trait3: ?Trait1 {} + | ^^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `?Trait` is not permitted in trait object types + --> $DIR/feature-gate-allow-maybe-polarity.rs:8:28 + | +LL | fn foo(_: Box) {} + | ^^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/feature-gate-allow-maybe-polarity.rs:10:11 + | +LL | fn bar(_: T) {} + | ^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/maybe-bounds.stderr b/tests/ui/maybe-bounds.stderr index 1d823b6acb283..04089db4c10d8 100644 --- a/tests/ui/maybe-bounds.stderr +++ b/tests/ui/maybe-bounds.stderr @@ -1,22 +1,30 @@ -error: `?Trait` is not permitted in supertraits +error[E0658]: `?Trait` is not permitted in supertraits --> $DIR/maybe-bounds.rs:1:11 | LL | trait Tr: ?Sized {} | ^^^^^^ | - = note: traits are `?Sized` by default + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bounds.rs:4:20 | LL | type A1 = dyn Tr + (?Sized); | ^^^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bounds.rs:6:28 | LL | type A2 = dyn for<'a> Tr + (?Sized); | ^^^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr index 3134746b930ac..9b2ccc914f1c0 100644 --- a/tests/ui/parser/trait-object-trait-parens.stderr +++ b/tests/ui/parser/trait-object-trait-parens.stderr @@ -1,20 +1,29 @@ -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:8:24 | LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; | ^^^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:13:16 | LL | let _: Box Trait<'a>) + (Obj)>; | ^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:18:44 | LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; | ^^^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: trait objects without an explicit `dyn` are deprecated --> $DIR/trait-object-trait-parens.rs:8:16 @@ -91,4 +100,5 @@ LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; error: aborting due to 6 previous errors; 3 warnings emitted -For more information about this error, try `rustc --explain E0225`. +Some errors have detailed explanations: E0225, E0658. +For more information about an error, try `rustc --explain E0225`. diff --git a/tests/ui/traits/maybe-polarity-pass.rs b/tests/ui/traits/maybe-polarity-pass.rs new file mode 100644 index 0000000000000..58e88f6242b5f --- /dev/null +++ b/tests/ui/traits/maybe-polarity-pass.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(auto_traits)] +#![feature(negative_impls)] +#![feature(allow_maybe_polarity)] + +trait Trait1 {} +auto trait Trait2 {} + +trait Trait3 : ?Trait1 {} +fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {} +fn bar(_: &T) {} + +struct S; +impl !Trait2 for S {} +impl Trait1 for S {} +impl Trait3 for S {} + +fn main() { + foo(Box::new(S)); + bar(&S); +} diff --git a/tests/ui/traits/wf-object/maybe-bound.stderr b/tests/ui/traits/wf-object/maybe-bound.stderr index 2fe3f0fc39f40..b31deb9ba416e 100644 --- a/tests/ui/traits/wf-object/maybe-bound.stderr +++ b/tests/ui/traits/wf-object/maybe-bound.stderr @@ -1,32 +1,48 @@ -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:5:15 | LL | type _0 = dyn ?Sized + Foo; | ^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:8:21 | LL | type _1 = dyn Foo + ?Sized; | ^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:11:21 | LL | type _2 = dyn Foo + ?Sized + ?Sized; | ^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:11:30 | LL | type _2 = dyn Foo + ?Sized + ?Sized; | ^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bound.rs:15:15 | LL | type _3 = dyn ?Sized + Foo; | ^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/wf-object/only-maybe-bound.stderr b/tests/ui/traits/wf-object/only-maybe-bound.stderr index cbc41feec1e8c..c08271a4aa842 100644 --- a/tests/ui/traits/wf-object/only-maybe-bound.stderr +++ b/tests/ui/traits/wf-object/only-maybe-bound.stderr @@ -1,8 +1,11 @@ -error: `?Trait` is not permitted in trait object types +error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/only-maybe-bound.rs:3:15 | LL | type _0 = dyn ?Sized; | ^^^^^^ + | + = help: add `#![feature(allow_maybe_polarity)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0224]: at least one trait is required for an object type --> $DIR/only-maybe-bound.rs:3:11 @@ -12,4 +15,5 @@ LL | type _0 = dyn ?Sized; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0224`. +Some errors have detailed explanations: E0224, E0658. +For more information about an error, try `rustc --explain E0224`.