From c927743b7b7bd382836dcce2d1140a7e829dc3d0 Mon Sep 17 00:00:00 2001 From: bohan Date: Tue, 6 Jun 2023 23:11:08 +0800 Subject: [PATCH 01/11] fix(expand): prevent infinity loop in macro containing only "///" --- compiler/rustc_expand/src/mbe/macro_parser.rs | 1 + compiler/rustc_expand/src/mbe/macro_rules.rs | 1 + tests/ui/macros/issue-112342-1.rs | 36 +++++++++++++++++++ tests/ui/macros/issue-112342-1.stderr | 29 +++++++++++++++ tests/ui/macros/issue-112342-2.rs | 28 +++++++++++++++ 5 files changed, 95 insertions(+) create mode 100644 tests/ui/macros/issue-112342-1.rs create mode 100644 tests/ui/macros/issue-112342-1.stderr create mode 100644 tests/ui/macros/issue-112342-2.rs diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 1c222fb4a89..f0e67cfd50e 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -249,6 +249,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec { } /// A single matcher position, representing the state of matching. +#[derive(Debug)] struct MatcherPos { /// The index into `TtParser::locs`, which represents the "dot". idx: usize, diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e4c65a2049b..576d636d489 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -647,6 +647,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| match seq_tt { TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true, + TokenTree::Token(t) => matches!(t, Token { kind: DocComment(..), .. }), TokenTree::Sequence(_, sub_seq) => { sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne diff --git a/tests/ui/macros/issue-112342-1.rs b/tests/ui/macros/issue-112342-1.rs new file mode 100644 index 00000000000..14fe9bbd97a --- /dev/null +++ b/tests/ui/macros/issue-112342-1.rs @@ -0,0 +1,36 @@ +// same as #95267, ignore doc comment although it's a bug. + +macro_rules! m1 { + ( + $( + /// + )* + //~^^^ERROR repetition matches empty token tree + ) => {}; +} + +m1! {} + +macro_rules! m2 { + ( + $( + /// + )+ + //~^^^ERROR repetition matches empty token tree + ) => {}; +} + +m2! {} + +macro_rules! m3 { + ( + $( + /// + )? + //~^^^ERROR repetition matches empty token tree + ) => {}; +} + +m3! {} + +fn main() {} diff --git a/tests/ui/macros/issue-112342-1.stderr b/tests/ui/macros/issue-112342-1.stderr new file mode 100644 index 00000000000..1ba7c0ffd3b --- /dev/null +++ b/tests/ui/macros/issue-112342-1.stderr @@ -0,0 +1,29 @@ +error: repetition matches empty token tree + --> $DIR/issue-112342-1.rs:5:10 + | +LL | $( + | __________^ +LL | | /// +LL | | )* + | |_________^ + +error: repetition matches empty token tree + --> $DIR/issue-112342-1.rs:16:10 + | +LL | $( + | __________^ +LL | | /// +LL | | )+ + | |_________^ + +error: repetition matches empty token tree + --> $DIR/issue-112342-1.rs:27:10 + | +LL | $( + | __________^ +LL | | /// +LL | | )? + | |_________^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/issue-112342-2.rs b/tests/ui/macros/issue-112342-2.rs new file mode 100644 index 00000000000..1e1d953fa52 --- /dev/null +++ b/tests/ui/macros/issue-112342-2.rs @@ -0,0 +1,28 @@ +// check-pass + +// same as #95267, ignore doc comment although it's a bug. + +macro_rules! m1 { + ( + $( + /// + $expr: expr, + )* + ) => {}; +} + +m1! {} + +macro_rules! m2 { + ( + $( + /// + $expr: expr, + /// + )* + ) => {}; +} + +m2! {} + +fn main() {} From e0acff796a9221bc4d6769e3db5bf158647ef0e1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 31 May 2023 01:02:32 +0000 Subject: [PATCH 02/11] New trait solver is a property of inference context --- .../src/region_infer/opaque_types.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_hir_analysis/src/autoderef.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_hir_typeck/src/writeback.rs | 4 +-- compiler/rustc_infer/src/infer/at.rs | 1 + compiler/rustc_infer/src/infer/combine.rs | 34 +++++++++---------- compiler/rustc_infer/src/infer/equate.rs | 2 +- compiler/rustc_infer/src/infer/lattice.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 17 ++++++++++ .../rustc_infer/src/infer/nll_relate/mod.rs | 6 ++-- .../rustc_infer/src/infer/opaque_types.rs | 6 ++-- compiler/rustc_infer/src/infer/projection.rs | 2 +- compiler/rustc_infer/src/infer/sub.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- .../src/solve/eval_ctxt.rs | 1 + .../src/traits/error_reporting/mod.rs | 2 +- .../src/traits/query/evaluate_obligation.rs | 2 +- .../src/traits/query/type_op/mod.rs | 2 +- .../src/traits/select/mod.rs | 4 +-- .../src/traits/structural_normalize.rs | 2 +- .../rustc_traits/src/evaluate_obligation.rs | 2 +- 23 files changed, 61 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 13e346b86bc..a561496b026 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -285,7 +285,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let infcx = self .tcx .infer_ctxt() - .with_opaque_type_inference(if self.tcx.trait_solver_next() { + .with_opaque_type_inference(if self.next_trait_solver() { DefiningAnchor::Bind(def_id) } else { DefiningAnchor::Bubble diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 908ff3da5ca..a2f95c19cf5 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -188,7 +188,7 @@ pub(crate) fn type_check<'mir, 'tcx>( // FIXME(-Ztrait-solver=next): A bit dubious that we're only registering // predefined opaques in the typeck root. - if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) { + if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { checker.register_predefined_opaques_in_new_solver(); } diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index d6d1498d708..f624118a4f1 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // NOTE: we may still need to normalize the built-in deref in case // we have some type like `&::Assoc`, since users of // autoderef expect this type to have been structurally normalized. - if self.infcx.tcx.trait_solver_next() + if self.infcx.next_trait_solver() && let ty::Alias(ty::Projection, _) = ty.kind() { let (normalized_ty, obligations) = self.structurally_normalize(ty)?; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ba49e0c4161..81231e8fe06 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -156,7 +156,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // In the new solver, lazy norm may allow us to shallowly equate // more types, but we emit possibly impossible-to-satisfy obligations. // Filter these cases out to make sure our coercion is more accurate. - if self.tcx.trait_solver_next() { + if self.next_trait_solver() { if let Ok(res) = &res { for obligation in &res.obligations { if !self.predicate_may_hold(&obligation) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 38ddb7e7604..fb56b7e74cb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1476,7 +1476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let mut ty = self.resolve_vars_with_obligations(ty); - if self.tcx.trait_solver_next() + if self.next_trait_solver() && let ty::Alias(ty::Projection, _) = ty.kind() { match self diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 964acc4eb77..6a3a46c778a 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -591,7 +591,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .insert(opaque_type_key, hidden_type) && last_opaque_ty.ty != hidden_type.ty { - assert!(!self.tcx().trait_solver_next()); + assert!(!self.fcx.next_trait_solver()); hidden_type .report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx()) .stash( @@ -812,7 +812,7 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match self.fcx.fully_resolve(t) { - Ok(t) if self.fcx.tcx.trait_solver_next() => { + Ok(t) if self.fcx.next_trait_solver() => { // We must normalize erasing regions here, since later lints // expect that types that show up in the typeck are fully // normalized. diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 6b2dd0a2b4f..1f0bf4f9887 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -82,6 +82,7 @@ impl<'tcx> InferCtxt<'tcx> { in_snapshot: self.in_snapshot.clone(), universe: self.universe.clone(), intercrate: self.intercrate, + next_trait_solver: self.next_trait_solver, } } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index ed532aa2e8b..ccfc44a7e44 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -109,11 +109,11 @@ impl<'tcx> InferCtxt<'tcx> { | ( ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), ty::Alias(AliasKind::Projection, _), - ) if self.tcx.trait_solver_next() => { + ) if self.next_trait_solver() => { bug!() } - (_, ty::Alias(..)) | (ty::Alias(..), _) if self.tcx.trait_solver_next() => { + (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => { relation.register_type_relate_obligation(a, b); Ok(a) } @@ -227,9 +227,22 @@ impl<'tcx> InferCtxt<'tcx> { return self.unify_const_variable(vid, a, relation.param_env()); } (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) - if self.tcx.features().generic_const_exprs || self.tcx.trait_solver_next() => + if self.tcx.features().generic_const_exprs || self.next_trait_solver() => { - relation.register_const_equate_obligation(a, b); + let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) }; + + relation.register_predicates([ty::Binder::dummy( + if self.next_trait_solver() { + ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ) + } else { + ty::PredicateKind::ConstEquate(a, b) + }, + )]); + return Ok(b); } _ => {} @@ -453,19 +466,6 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { /// be used if control over the obligation causes is required. fn register_predicates(&mut self, obligations: impl IntoIterator>); - /// Register an obligation that both constants must be equal to each other. - /// - /// If they aren't equal then the relation doesn't hold. - fn register_const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { - let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - - self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() { - ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate) - } else { - ty::PredicateKind::ConstEquate(a, b) - })]); - } - /// Register an obligation that both types must be related to each other according to /// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`] fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 42dfe4f6bb8..495c250a77d 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -105,7 +105,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if self.fields.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() - && !self.tcx().trait_solver_next() => + && !self.fields.infcx.next_trait_solver() => { self.fields.obligations.extend( infcx diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index 7190d33d299..9ef35429fe3 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -113,7 +113,7 @@ where | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() - && !this.tcx().trait_solver_next() => + && !this.infcx().next_trait_solver() => { this.register_obligations( infcx diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 447d4c9f84b..7041e21a381 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -330,6 +330,8 @@ pub struct InferCtxt<'tcx> { /// there is no type that the user could *actually name* that /// would satisfy it. This avoids crippling inference, basically. pub intercrate: bool, + + next_trait_solver: bool, } /// See the `error_reporting` module for more details. @@ -545,6 +547,9 @@ pub struct InferCtxtBuilder<'tcx> { skip_leak_check: bool, /// Whether we are in coherence mode. intercrate: bool, + /// Whether we should use the new trait solver in the local inference context, + /// which affects things like which solver is used in `predicate_may_hold`. + next_trait_solver: bool, } pub trait TyCtxtInferExt<'tcx> { @@ -559,6 +564,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { considering_regions: true, skip_leak_check: false, intercrate: false, + next_trait_solver: self.next_trait_solver_globally(), } } } @@ -575,6 +581,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self { + self.next_trait_solver = next_trait_solver; + self + } + pub fn intercrate(mut self, intercrate: bool) -> Self { self.intercrate = intercrate; self @@ -617,6 +628,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { considering_regions, skip_leak_check, intercrate, + next_trait_solver, } = *self; InferCtxt { tcx, @@ -634,6 +646,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { in_snapshot: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, + next_trait_solver, } } } @@ -670,6 +683,10 @@ pub struct CombinedSnapshot<'tcx> { } impl<'tcx> InferCtxt<'tcx> { + pub fn next_trait_solver(&self) -> bool { + self.next_trait_solver + } + /// Creates a `TypeErrCtxt` for emitting various inference errors. /// During typeck, use `FnCtxt::err_ctxt` instead. pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index d3fd01b9642..71c07f31bc9 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -491,12 +491,12 @@ where ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id || infcx.tcx.trait_solver_next() => { + ) if a_def_id == b_def_id || infcx.next_trait_solver() => { infcx.super_combine_tys(self, a, b).or_else(|err| { // This behavior is only there for the old solver, the new solver // shouldn't ever fail. Instead, it unconditionally emits an // alias-relate goal. - assert!(!self.tcx().trait_solver_next()); + assert!(!self.infcx.next_trait_solver()); self.tcx().sess.delay_span_bug( self.delegate.span(), "failure to relate an opaque to itself should result in an error later on", @@ -506,7 +506,7 @@ where } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if def_id.is_local() && !self.tcx().trait_solver_next() => + if def_id.is_local() && !self.infcx.next_trait_solver() => { self.relate_opaques(a, b) } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 105a3f08c82..a9ead429f4c 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -49,7 +49,7 @@ impl<'tcx> InferCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> InferOk<'tcx, T> { // We handle opaque types differently in the new solver. - if self.tcx.trait_solver_next() { + if self.next_trait_solver() { return InferOk { value, obligations: vec![] }; } @@ -578,7 +578,7 @@ impl<'tcx> InferCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, hidden_ty: Ty<'tcx>, ) -> InferResult<'tcx, ()> { - assert!(self.tcx.trait_solver_next()); + assert!(self.next_trait_solver()); let origin = self .opaque_type_origin(opaque_type_key.def_id) .expect("should be called for defining usages only"); @@ -614,7 +614,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::Alias(ty::Projection, projection_ty) if !projection_ty.has_escaping_bound_vars() && !tcx.is_impl_trait_in_trait(projection_ty.def_id) - && !tcx.trait_solver_next() => + && !self.next_trait_solver() => { self.infer_projection( param_env, diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index fa6529dfa93..4f8c9188cf8 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -21,7 +21,7 @@ impl<'tcx> InferCtxt<'tcx> { recursion_depth: usize, obligations: &mut Vec>, ) -> Ty<'tcx> { - if self.tcx.trait_solver_next() { + if self.next_trait_solver() { // FIXME(-Ztrait-solver=next): Instead of branching here, // completely change the normalization routine with the new solver. // diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index ceafafb5582..d9f9d2aabdb 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -132,7 +132,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if self.fields.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() - && !self.tcx().trait_solver_next() => + && !self.fields.infcx.next_trait_solver() => { self.fields.obligations.extend( infcx diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index bf6f21968d7..33ca68a0d03 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2333,7 +2333,7 @@ impl<'tcx> TyCtxt<'tcx> { self.opt_local_def_id_to_hir_id(local_def_id).unwrap() } - pub fn trait_solver_next(self) -> bool { + pub fn next_trait_solver_globally(self) -> bool { self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index bc93b9e99ad..3001d9f1b1f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -187,6 +187,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let (ref infcx, input, var_values) = tcx .infer_ctxt() .intercrate(intercrate) + .with_next_trait_solver(true) .with_opaque_type_inference(canonical_input.value.anchor) .build_with_canonical(DUMMY_SP, &canonical_input); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 01c74be7057..c4481b39e14 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1047,7 +1047,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // (which may fail). span_bug!(span, "WF predicate not satisfied for {:?}", ty); } - TraitSolver::Chalk | TraitSolver::Next => { + TraitSolver::Chalk | TraitSolver::Next | TraitSolver::NextCoherence => { // FIXME: we'll need a better message which takes into account // which bounds actually failed to hold. self.tcx.sess.struct_span_err( diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index a8a74d7501a..f8ceee50054 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -78,7 +78,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { _ => obligation.param_env.without_const(), }; - if self.tcx.trait_solver_next() { + if self.next_trait_solver() { self.probe(|snapshot| { let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); fulfill_cx.register_predicate_obligation(self, obligation.clone()); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 642fdec2d9a..9d7933e23a8 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -146,7 +146,7 @@ where infcx: &InferCtxt<'tcx>, span: Span, ) -> Result, ErrorGuaranteed> { - if infcx.tcx.trait_solver_next() { + if infcx.next_trait_solver() { return Ok(scrape_region_constraints( infcx, |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 42c1b629ac2..25e5b5e17de 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -539,7 +539,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluation_probe(|this| { let goal = this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); - let mut result = if this.tcx().trait_solver_next() { + let mut result = if this.infcx.next_trait_solver() { this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])? } else { this.evaluate_predicate_recursively( @@ -593,7 +593,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { where I: IntoIterator> + std::fmt::Debug, { - if self.tcx().trait_solver_next() { + if self.infcx.next_trait_solver() { self.evaluate_predicates_recursively_in_new_solver(predicates) } else { let mut result = EvaluatedToOk; diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index af8dd0da579..84746eba3ec 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -21,7 +21,7 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { ) -> Result, Vec>> { assert!(!ty.is_ty_var(), "should have resolved vars before calling"); - if self.infcx.tcx.trait_solver_next() { + if self.infcx.next_trait_solver() { while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() { let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::NormalizeProjectionType, diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index f5b2753b797..73756caf372 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -16,7 +16,7 @@ fn evaluate_obligation<'tcx>( tcx: TyCtxt<'tcx>, canonical_goal: CanonicalPredicateGoal<'tcx>, ) -> Result { - assert!(!tcx.trait_solver_next()); + assert!(!tcx.next_trait_solver_globally()); debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); // HACK This bubble is required for this tests to pass: // impl-trait/issue99642.rs From b637048a89654d105a17b6b6f1a060fd8dcfd093 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 31 May 2023 01:02:40 +0000 Subject: [PATCH 03/11] Add -Ztrait-solver=next-coherence --- compiler/rustc_middle/src/ty/context.rs | 8 ++++++++ compiler/rustc_session/src/config.rs | 2 ++ compiler/rustc_session/src/options.rs | 1 + compiler/rustc_trait_selection/src/traits/coherence.rs | 1 + compiler/rustc_trait_selection/src/traits/engine.rs | 2 ++ 5 files changed, 14 insertions(+) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 33ca68a0d03..4ee543bbfb6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2337,6 +2337,14 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next } + pub fn next_trait_solver_in_coherence(self) -> bool { + matches!( + self.sess.opts.unstable_opts.trait_solver, + rustc_session::config::TraitSolver::Next + | rustc_session::config::TraitSolver::NextCoherence + ) + } + pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool { self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0ce83e79097..24291301a32 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -610,6 +610,8 @@ pub enum TraitSolver { Chalk, /// Experimental trait solver in `rustc_trait_selection::solve` Next, + /// Use the new trait solver during coherence + NextCoherence, } pub enum Input { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7cc2b2c880c..201066e3950 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -986,6 +986,7 @@ mod parse { Some("classic") => *slot = TraitSolver::Classic, Some("chalk") => *slot = TraitSolver::Chalk, Some("next") => *slot = TraitSolver::Next, + Some("next-coherence") => *slot = TraitSolver::NextCoherence, // default trait solver is subject to change.. Some("default") => *slot = TraitSolver::Classic, _ => return false, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index d6fd457de06..2c793ea33dc 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -182,6 +182,7 @@ fn overlap<'tcx>( .with_opaque_type_inference(DefiningAnchor::Bubble) .skip_leak_check(skip_leak_check.is_yes()) .intercrate(true) + .with_next_trait_solver(tcx.next_trait_solver_in_coherence()) .build(); let selcx = &mut SelectionContext::new(&infcx); if track_ambiguity_causes.is_yes() { diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 2c5ffd664fe..1ddff3b66d5 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -35,6 +35,7 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Box { match tcx.sess.opts.unstable_opts.trait_solver { TraitSolver::Classic => Box::new(FulfillmentContext::new()), + TraitSolver::NextCoherence => Box::new(FulfillmentContext::new()), TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new()), TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()), } @@ -43,6 +44,7 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box { match tcx.sess.opts.unstable_opts.trait_solver { TraitSolver::Classic => Box::new(FulfillmentContext::new_in_snapshot()), + TraitSolver::NextCoherence => Box::new(FulfillmentContext::new_in_snapshot()), TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new_in_snapshot()), TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()), } From 3d4da98273553b2307d8ce3a03c476e459aa3f45 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 31 May 2023 01:21:38 +0000 Subject: [PATCH 04/11] Make TraitEngine::new use the right solver, add compare mode --- compiler/rustc_hir_analysis/src/autoderef.rs | 3 +- .../rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_typeck/src/inherited.rs | 2 +- compiler/rustc_infer/src/infer/combine.rs | 20 ++++---- .../src/traits/engine.rs | 48 ++++++++++++------- compiler/rustc_traits/src/codegen.rs | 2 +- src/tools/compiletest/src/common.rs | 1 + src/tools/compiletest/src/runtest.rs | 3 ++ 8 files changed, 49 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index f624118a4f1..6eb18aecd65 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -161,8 +161,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { &self, ty: Ty<'tcx>, ) -> Option<(Ty<'tcx>, Vec>)> { - let tcx = self.infcx.tcx; - let mut fulfill_cx = >::new_in_snapshot(tcx); + let mut fulfill_cx = >::new_in_snapshot(self.infcx); let cause = traits::ObligationCause::misc(self.span, self.body_id); let normalized_ty = match self diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4a1f8ece7b2..17be5fe66cf 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1549,7 +1549,7 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) .build(); - let mut fulfillment_cx = >::new(infcx.tcx); + let mut fulfillment_cx = >::new(&infcx); for (predicate, cause) in generator_interior_predicates { let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); fulfillment_cx.register_predicate_obligation(&infcx, obligation); diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 294c3bb78a5..aa4f90b4ad8 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -86,8 +86,8 @@ impl<'tcx> Inherited<'tcx> { Inherited { typeck_results, + fulfillment_cx: RefCell::new(>::new(&infcx)), infcx, - fulfillment_cx: RefCell::new(>::new(tcx)), locals: RefCell::new(Default::default()), deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index ccfc44a7e44..7a80ee98cb3 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -231,17 +231,15 @@ impl<'tcx> InferCtxt<'tcx> { { let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) }; - relation.register_predicates([ty::Binder::dummy( - if self.next_trait_solver() { - ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Equate, - ) - } else { - ty::PredicateKind::ConstEquate(a, b) - }, - )]); + relation.register_predicates([ty::Binder::dummy(if self.next_trait_solver() { + ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ) + } else { + ty::PredicateKind::ConstEquate(a, b) + })]); return Ok(b); } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 1ddff3b66d5..90699c3cadc 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -27,26 +27,42 @@ use rustc_session::config::TraitSolver; use rustc_span::Span; pub trait TraitEngineExt<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> Box; - fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box; + fn new(infcx: &InferCtxt<'tcx>) -> Box; + fn new_in_snapshot(infcx: &InferCtxt<'tcx>) -> Box; } impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> Box { - match tcx.sess.opts.unstable_opts.trait_solver { - TraitSolver::Classic => Box::new(FulfillmentContext::new()), - TraitSolver::NextCoherence => Box::new(FulfillmentContext::new()), - TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new()), - TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()), + fn new(infcx: &InferCtxt<'tcx>) -> Box { + match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) { + (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => { + Box::new(FulfillmentContext::new()) + } + (TraitSolver::Next | TraitSolver::NextCoherence, true) => { + Box::new(NextFulfillmentCtxt::new()) + } + (TraitSolver::Chalk, false) => Box::new(ChalkFulfillmentContext::new()), + _ => bug!( + "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})", + infcx.tcx.sess.opts.unstable_opts.trait_solver, + infcx.next_trait_solver() + ), } } - fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box { - match tcx.sess.opts.unstable_opts.trait_solver { - TraitSolver::Classic => Box::new(FulfillmentContext::new_in_snapshot()), - TraitSolver::NextCoherence => Box::new(FulfillmentContext::new_in_snapshot()), - TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new_in_snapshot()), - TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()), + fn new_in_snapshot(infcx: &InferCtxt<'tcx>) -> Box { + match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) { + (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => { + Box::new(FulfillmentContext::new_in_snapshot()) + } + (TraitSolver::Next | TraitSolver::NextCoherence, true) => { + Box::new(NextFulfillmentCtxt::new()) + } + (TraitSolver::Chalk, false) => Box::new(ChalkFulfillmentContext::new_in_snapshot()), + _ => bug!( + "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})", + infcx.tcx.sess.opts.unstable_opts.trait_solver, + infcx.next_trait_solver() + ), } } } @@ -60,11 +76,11 @@ pub struct ObligationCtxt<'a, 'tcx> { impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - Self { infcx, engine: RefCell::new(>::new(infcx.tcx)) } + Self { infcx, engine: RefCell::new(>::new(infcx)) } } pub fn new_in_snapshot(infcx: &'a InferCtxt<'tcx>) -> Self { - Self { infcx, engine: RefCell::new(>::new_in_snapshot(infcx.tcx)) } + Self { infcx, engine: RefCell::new(>::new_in_snapshot(infcx)) } } pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index ddba03b0b12..5f84acc8a04 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -55,7 +55,7 @@ pub fn codegen_select_candidate<'tcx>( // Currently, we use a fulfillment context to completely resolve // all nested obligations. This is because they can inform the // inference of the impl's type parameters. - let mut fulfill_cx = >::new(tcx); + let mut fulfill_cx = >::new(&infcx); let impl_source = selection.map(|predicate| { fulfill_cx.register_predicate_obligation(&infcx, predicate); }); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index f796c898731..96fe720630c 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -108,6 +108,7 @@ string_enum! { Polonius => "polonius", Chalk => "chalk", NextSolver => "next-solver", + NextSolverCoherence => "next-solver-coherence", SplitDwarf => "split-dwarf", SplitDwarfSingle => "split-dwarf-single", } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 923b2e63f2e..6582b534488 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2127,6 +2127,9 @@ impl<'test> TestCx<'test> { Some(CompareMode::NextSolver) => { rustc.args(&["-Ztrait-solver=next"]); } + Some(CompareMode::NextSolverCoherence) => { + rustc.args(&["-Ztrait-solver=next-coherence"]); + } Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => { rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]); } From aabdeedc7c812388b30575a5f53292128f4f7464 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 31 May 2023 01:39:20 +0000 Subject: [PATCH 05/11] bless coherence test --- ...ion-default-items-drop-coherence.coherence.stderr | 12 ++++++++++++ ...lization-default-items-drop-coherence.next.stderr | 12 ++++++++++++ .../specialization-default-items-drop-coherence.rs | 9 +++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/ui/specialization/specialization-default-items-drop-coherence.coherence.stderr create mode 100644 tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.coherence.stderr b/tests/ui/specialization/specialization-default-items-drop-coherence.coherence.stderr new file mode 100644 index 00000000000..578db0cc65e --- /dev/null +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.coherence.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Overlap` for type `u32` + --> $DIR/specialization-default-items-drop-coherence.rs:29:1 + | +LL | impl Overlap for u32 { + | -------------------- first implementation here +... +LL | impl Overlap for ::Id { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr b/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr new file mode 100644 index 00000000000..578db0cc65e --- /dev/null +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Overlap` for type `u32` + --> $DIR/specialization-default-items-drop-coherence.rs:29:1 + | +LL | impl Overlap for u32 { + | -------------------- first implementation here +... +LL | impl Overlap for ::Id { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.rs b/tests/ui/specialization/specialization-default-items-drop-coherence.rs index 16ad942d5ab..44c598f19cb 100644 --- a/tests/ui/specialization/specialization-default-items-drop-coherence.rs +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.rs @@ -1,5 +1,8 @@ -// check-pass -// known-bug: #105782 +// revisions: classic coherence next +//[next] compile-flags: -Ztrait-solver=next +//[coherence] compile-flags: -Ztrait-solver=next-coherence +//[classic] check-pass +//[classic] known-bug: #105782 // Should fail. Default items completely drop candidates instead of ambiguity, // which is unsound during coherence, since coherence requires completeness. @@ -24,6 +27,8 @@ impl Overlap for u32 { } impl Overlap for ::Id { + //[coherence]~^ ERROR conflicting implementations of trait `Overlap` for type `u32` + //[next]~^^ ERROR conflicting implementations of trait `Overlap` for type `u32` type Assoc = Box; } From 7a2cdf20e42c5b2a4d0f259eab8968cda7ae55c2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 27 May 2023 19:05:09 +0000 Subject: [PATCH 06/11] Move alias-relate to its own module --- .../src/solve/alias_relate.rs | 146 ++++++++++++++++++ .../rustc_trait_selection/src/solve/mod.rs | 137 +--------------- 2 files changed, 147 insertions(+), 136 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/solve/alias_relate.rs diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs new file mode 100644 index 00000000000..59ab3bc3a72 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -0,0 +1,146 @@ +use super::{EvalCtxt, SolverMode}; +use rustc_infer::traits::query::NoSolution; +use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; +use rustc_middle::ty; + +/// We may need to invert the alias relation direction if dealing an alias on the RHS. +#[derive(Debug)] +enum Invert { + No, + Yes, +} + +impl<'tcx> EvalCtxt<'_, 'tcx> { + #[instrument(level = "debug", skip(self), ret)] + pub(super) fn compute_alias_relate_goal( + &mut self, + goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, + ) -> QueryResult<'tcx> { + let tcx = self.tcx(); + let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; + if lhs.is_infer() || rhs.is_infer() { + bug!( + "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated" + ); + } + + match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) { + (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"), + + // RHS is not a projection, only way this is true is if LHS normalizes-to RHS + (Some(alias_lhs), None) => self.assemble_normalizes_to_candidate( + param_env, + alias_lhs, + rhs, + direction, + Invert::No, + ), + + // LHS is not a projection, only way this is true is if RHS normalizes-to LHS + (None, Some(alias_rhs)) => self.assemble_normalizes_to_candidate( + param_env, + alias_rhs, + lhs, + direction, + Invert::Yes, + ), + + (Some(alias_lhs), Some(alias_rhs)) => { + debug!("both sides are aliases"); + + let mut candidates = Vec::new(); + // LHS normalizes-to RHS + candidates.extend(self.assemble_normalizes_to_candidate( + param_env, + alias_lhs, + rhs, + direction, + Invert::No, + )); + // RHS normalizes-to RHS + candidates.extend(self.assemble_normalizes_to_candidate( + param_env, + alias_rhs, + lhs, + direction, + Invert::Yes, + )); + // Relate via substs + let subst_relate_response = self + .assemble_subst_relate_candidate(param_env, alias_lhs, alias_rhs, direction); + candidates.extend(subst_relate_response); + debug!(?candidates); + + if let Some(merged) = self.try_merge_responses(&candidates) { + Ok(merged) + } else { + // When relating two aliases and we have ambiguity, we prefer + // relating the generic arguments of the aliases over normalizing + // them. This is necessary for inference during typeck. + // + // As this is incomplete, we must not do so during coherence. + match (self.solver_mode(), subst_relate_response) { + (SolverMode::Normal, Ok(response)) => Ok(response), + (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => { + self.flounder(&candidates) + } + } + } + } + } + } + + #[instrument(level = "debug", skip(self), ret)] + fn assemble_normalizes_to_candidate( + &mut self, + param_env: ty::ParamEnv<'tcx>, + alias: ty::AliasTy<'tcx>, + other: ty::Term<'tcx>, + direction: ty::AliasRelationDirection, + invert: Invert, + ) -> QueryResult<'tcx> { + self.probe(|ecx| { + let other = match direction { + // This is purely an optimization. + ty::AliasRelationDirection::Equate => other, + + ty::AliasRelationDirection::Subtype => { + let fresh = ecx.next_term_infer_of_kind(other); + let (sub, sup) = match invert { + Invert::No => (fresh, other), + Invert::Yes => (other, fresh), + }; + ecx.sub(param_env, sub, sup)?; + fresh + } + }; + ecx.add_goal(Goal::new( + ecx.tcx(), + param_env, + ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + + fn assemble_subst_relate_candidate( + &mut self, + param_env: ty::ParamEnv<'tcx>, + alias_lhs: ty::AliasTy<'tcx>, + alias_rhs: ty::AliasTy<'tcx>, + direction: ty::AliasRelationDirection, + ) -> QueryResult<'tcx> { + self.probe(|ecx| { + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(param_env, alias_lhs, alias_rhs)?; + } + } + + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } +} diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 56a254d9c07..f4c29c837b8 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, }; +mod alias_relate; mod assembly; mod canonicalize; mod eval_ctxt; @@ -154,142 +155,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self), ret)] - fn compute_alias_relate_goal( - &mut self, - goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, - ) -> QueryResult<'tcx> { - let tcx = self.tcx(); - // We may need to invert the alias relation direction if dealing an alias on the RHS. - #[derive(Debug)] - enum Invert { - No, - Yes, - } - let evaluate_normalizes_to = - |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| { - let span = tracing::span!( - tracing::Level::DEBUG, - "compute_alias_relate_goal(evaluate_normalizes_to)", - ?alias, - ?other, - ?direction, - ?invert - ); - let _enter = span.enter(); - let result = ecx.probe(|ecx| { - let other = match direction { - // This is purely an optimization. - ty::AliasRelationDirection::Equate => other, - - ty::AliasRelationDirection::Subtype => { - let fresh = ecx.next_term_infer_of_kind(other); - let (sub, sup) = match invert { - Invert::No => (fresh, other), - Invert::Yes => (other, fresh), - }; - ecx.sub(goal.param_env, sub, sup)?; - fresh - } - }; - ecx.add_goal(goal.with( - tcx, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty: alias, - term: other, - }), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }); - debug!(?result); - result - }; - - let (lhs, rhs, direction) = goal.predicate; - - if lhs.is_infer() || rhs.is_infer() { - bug!( - "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated" - ); - } - - match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) { - (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"), - - // RHS is not a projection, only way this is true is if LHS normalizes-to RHS - (Some(alias_lhs), None) => { - evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No) - } - - // LHS is not a projection, only way this is true is if RHS normalizes-to LHS - (None, Some(alias_rhs)) => { - evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes) - } - - (Some(alias_lhs), Some(alias_rhs)) => { - debug!("both sides are aliases"); - - let mut candidates = Vec::new(); - // LHS normalizes-to RHS - candidates.extend(evaluate_normalizes_to( - self, - alias_lhs, - rhs, - direction, - Invert::No, - )); - // RHS normalizes-to RHS - candidates.extend(evaluate_normalizes_to( - self, - alias_rhs, - lhs, - direction, - Invert::Yes, - )); - // Relate via substs - let subst_relate_response = self.probe(|ecx| { - let span = tracing::span!( - tracing::Level::DEBUG, - "compute_alias_relate_goal(relate_via_substs)", - ?alias_lhs, - ?alias_rhs, - ?direction - ); - let _enter = span.enter(); - - match direction { - ty::AliasRelationDirection::Equate => { - ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; - } - ty::AliasRelationDirection::Subtype => { - ecx.sub(goal.param_env, alias_lhs, alias_rhs)?; - } - } - - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }); - candidates.extend(subst_relate_response); - debug!(?candidates); - - if let Some(merged) = self.try_merge_responses(&candidates) { - Ok(merged) - } else { - // When relating two aliases and we have ambiguity, we prefer - // relating the generic arguments of the aliases over normalizing - // them. This is necessary for inference during typeck. - // - // As this is incomplete, we must not do so during coherence. - match (self.solver_mode(), subst_relate_response) { - (SolverMode::Normal, Ok(response)) => Ok(response), - (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => { - self.flounder(&candidates) - } - } - } - } - } - } - #[instrument(level = "debug", skip(self), ret)] fn compute_const_arg_has_type_goal( &mut self, From 3ea7c512bd1587006a1c196df841e9b7ec60fb0b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 27 May 2023 19:27:59 +0000 Subject: [PATCH 07/11] Fall back to bidirectional normalizes-to if no subst-eq in alias-eq goal --- .../src/solve/alias_relate.rs | 95 ++++++++++++++----- tests/ui/traits/new-solver/tait-eq-proj-2.rs | 21 ++++ tests/ui/traits/new-solver/tait-eq-proj.rs | 35 +++++++ tests/ui/traits/new-solver/tait-eq-tait.rs | 17 ++++ 4 files changed, 145 insertions(+), 23 deletions(-) create mode 100644 tests/ui/traits/new-solver/tait-eq-proj-2.rs create mode 100644 tests/ui/traits/new-solver/tait-eq-proj.rs create mode 100644 tests/ui/traits/new-solver/tait-eq-tait.rs diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 59ab3bc3a72..66a4d36a1e5 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -79,11 +79,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // them. This is necessary for inference during typeck. // // As this is incomplete, we must not do so during coherence. - match (self.solver_mode(), subst_relate_response) { - (SolverMode::Normal, Ok(response)) => Ok(response), - (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => { - self.flounder(&candidates) + match self.solver_mode() { + SolverMode::Normal => { + if let Ok(subst_relate_response) = subst_relate_response { + Ok(subst_relate_response) + } else if let Ok(bidirectional_normalizes_to_response) = self + .assemble_bidirectional_normalizes_to_candidate( + param_env, lhs, rhs, direction, + ) + { + Ok(bidirectional_normalizes_to_response) + } else { + self.flounder(&candidates) + } } + SolverMode::Coherence => self.flounder(&candidates), } } } @@ -100,29 +110,42 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { invert: Invert, ) -> QueryResult<'tcx> { self.probe(|ecx| { - let other = match direction { - // This is purely an optimization. - ty::AliasRelationDirection::Equate => other, - - ty::AliasRelationDirection::Subtype => { - let fresh = ecx.next_term_infer_of_kind(other); - let (sub, sup) = match invert { - Invert::No => (fresh, other), - Invert::Yes => (other, fresh), - }; - ecx.sub(param_env, sub, sup)?; - fresh - } - }; - ecx.add_goal(Goal::new( - ecx.tcx(), - param_env, - ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }), - )); + ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } + fn normalizes_to_inner( + &mut self, + param_env: ty::ParamEnv<'tcx>, + alias: ty::AliasTy<'tcx>, + other: ty::Term<'tcx>, + direction: ty::AliasRelationDirection, + invert: Invert, + ) -> Result<(), NoSolution> { + let other = match direction { + // This is purely an optimization. + ty::AliasRelationDirection::Equate => other, + + ty::AliasRelationDirection::Subtype => { + let fresh = self.next_term_infer_of_kind(other); + let (sub, sup) = match invert { + Invert::No => (fresh, other), + Invert::Yes => (other, fresh), + }; + self.sub(param_env, sub, sup)?; + fresh + } + }; + self.add_goal(Goal::new( + self.tcx(), + param_env, + ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }), + )); + + Ok(()) + } + fn assemble_subst_relate_candidate( &mut self, param_env: ty::ParamEnv<'tcx>, @@ -143,4 +166,30 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } + + fn assemble_bidirectional_normalizes_to_candidate( + &mut self, + param_env: ty::ParamEnv<'tcx>, + lhs: ty::Term<'tcx>, + rhs: ty::Term<'tcx>, + direction: ty::AliasRelationDirection, + ) -> QueryResult<'tcx> { + self.probe(|ecx| { + ecx.normalizes_to_inner( + param_env, + lhs.to_alias_ty(ecx.tcx()).unwrap(), + rhs, + direction, + Invert::No, + )?; + ecx.normalizes_to_inner( + param_env, + rhs.to_alias_ty(ecx.tcx()).unwrap(), + lhs, + direction, + Invert::Yes, + )?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } } diff --git a/tests/ui/traits/new-solver/tait-eq-proj-2.rs b/tests/ui/traits/new-solver/tait-eq-proj-2.rs new file mode 100644 index 00000000000..99a3d02bd1a --- /dev/null +++ b/tests/ui/traits/new-solver/tait-eq-proj-2.rs @@ -0,0 +1,21 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +#![feature(type_alias_impl_trait)] + +// Similar to tests/ui/traits/new-solver/tait-eq-proj.rs +// but check the alias-sub relation in the other direction. + +type Tait = impl Iterator; + +fn mk() -> T { todo!() } + +fn a() { + let x: Tait = mk(); + let mut array = mk(); + let mut z = IntoIterator::into_iter(array); + z = x; + array = [0i32; 32]; +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/tait-eq-proj.rs b/tests/ui/traits/new-solver/tait-eq-proj.rs new file mode 100644 index 00000000000..01141b2819a --- /dev/null +++ b/tests/ui/traits/new-solver/tait-eq-proj.rs @@ -0,0 +1,35 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +#![feature(type_alias_impl_trait)] + +type Tait = impl Iterator; + +/* + +Consider the goal - AliasRelate(Tait, <[i32; 32] as IntoIterator>::IntoIter) +which is registered on the line above. + +A. SubstRelate - fails (of course). + +B. NormalizesToRhs - Tait normalizes-to <[i32; 32] as IntoIterator>::IntoIter + * infer definition - Tait := <[i32; 32] as IntoIterator>::IntoIter + +C. NormalizesToLhs - <[i32; 32] as IntoIterator>::IntoIter normalizes-to Tait + * Find impl candidate, after substitute - std::array::IntoIter + * Equate std::array::IntoIter and Tait + * infer definition - Tait := std::array::IntoIter + +B and C are not equal, but they are equivalent modulo normalization. + +We get around this by evaluating both the NormalizesToRhs and NormalizesToLhs +goals together. Essentially: + A alias-relate B if A normalizes-to B and B normalizes-to A. + +*/ + +fn a() { + let _: Tait = IntoIterator::into_iter([0i32; 32]); +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/tait-eq-tait.rs b/tests/ui/traits/new-solver/tait-eq-tait.rs new file mode 100644 index 00000000000..532c4c39bd4 --- /dev/null +++ b/tests/ui/traits/new-solver/tait-eq-tait.rs @@ -0,0 +1,17 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +// Not exactly sure if this is the inference behavior we *want*, +// but it is a side-effect of the lazy normalization of TAITs. + +#![feature(type_alias_impl_trait)] + +type Tait = impl Sized; +type Tait2 = impl Sized; + +fn mk() -> T { todo!() } + +fn main() { + let x: Tait = 1u32; + let y: Tait2 = x; +} From 0f1aaef7e9a1776a81819ef4ae05b508fb12d572 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 3 Jun 2023 10:40:46 -0700 Subject: [PATCH 08/11] rustdoc: convert `if let Some()` that always matches to variable --- src/librustdoc/visit_ast.rs | 46 ++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index db353552893..22c8cc09243 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -14,7 +14,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use std::{iter, mem}; +use std::mem; use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt}; use crate::core; @@ -291,27 +291,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if !please_inline { let inherits_hidden = inherits_doc_hidden(tcx, res_did, None); // Only inline if requested or if the item would otherwise be stripped. - // - // If it's a doc hidden module, we need to keep it in case some of its inner items - // are re-exported. if (!is_private && !inherits_hidden) || ( is_hidden && + // If it's a doc hidden module, we need to keep it in case some of its inner items + // are re-exported. !matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. })) - ) { - return false; - } else if let Some(item_def_id) = reexport_chain(tcx, def_id, res_did).iter() - .flat_map(|reexport| reexport.id()).map(|id| id.expect_local()) - .chain(iter::once(res_did)).nth(1) && - item_def_id != def_id && - self - .cx - .cache - .effective_visibilities - .is_directly_public(tcx, item_def_id.to_def_id()) && - !tcx.is_doc_hidden(item_def_id) && - !inherits_doc_hidden(tcx, item_def_id, None) - { + ) || // The imported item is public and not `doc(hidden)` so no need to inline it. + self.reexport_public_and_not_hidden(def_id, res_did) + { return false; } } @@ -359,6 +347,28 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ret } + /// Returns `true` if the item is visible, meaning it's not `#[doc(hidden)]` or private. + /// + /// This function takes into account the entire re-export `use` chain, so it needs the + /// ID of the "leaf" `use` and the ID of the "root" item. + fn reexport_public_and_not_hidden( + &self, + import_def_id: LocalDefId, + target_def_id: LocalDefId, + ) -> bool { + let tcx = self.cx.tcx; + let item_def_id = reexport_chain(tcx, import_def_id, target_def_id) + .iter() + .flat_map(|reexport| reexport.id()) + .map(|id| id.expect_local()) + .nth(1) + .unwrap_or(target_def_id); + item_def_id != import_def_id + && self.cx.cache.effective_visibilities.is_directly_public(tcx, item_def_id.to_def_id()) + && !tcx.is_doc_hidden(item_def_id) + && !inherits_doc_hidden(tcx, item_def_id, None) + } + #[inline] fn add_to_current_mod( &mut self, From 70980929b480d6c13e23d79ad8de2ff0afbce60c Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 6 Jun 2023 19:24:33 +0000 Subject: [PATCH 09/11] Respect `RUST_BACKTRACE` for delayed bugs Sometimes, especially with MIR validation, the backtraces from delayed bugs are noise and make it harder to look at them. Respect the environment variable and don't print it when the user doesn't want it. --- compiler/rustc_errors/src/lib.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bf77ed81f9b..7a297ea0d5f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -383,7 +383,7 @@ pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; pub use diagnostic_impls::{ DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans, }; -use std::backtrace::Backtrace; +use std::backtrace::{Backtrace, BacktraceStatus}; /// A handler deals with errors and other compiler output. /// Certain errors (fatal, bug, unimpl) may cause immediate exit, @@ -1331,7 +1331,7 @@ impl HandlerInner { // once *any* errors were emitted (and truncate `delayed_span_bugs` // when an error is first emitted, also), but maybe there's a case // in which that's not sound? otherwise this is really inefficient. - let backtrace = std::backtrace::Backtrace::force_capture(); + let backtrace = std::backtrace::Backtrace::capture(); self.delayed_span_bugs .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); @@ -1620,7 +1620,7 @@ impl HandlerInner { if self.flags.report_delayed_bugs { self.emit_diagnostic(&mut diagnostic); } - let backtrace = std::backtrace::Backtrace::force_capture(); + let backtrace = std::backtrace::Backtrace::capture(); self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); } @@ -1739,7 +1739,17 @@ impl DelayedDiagnostic { } fn decorate(mut self) -> Diagnostic { - self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note)); + match self.note.status() { + BacktraceStatus::Captured => { + self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note)); + } + // Avoid the needless newline when no backtrace has been captured, + // the display impl should just be a single line. + _ => { + self.inner.note(format!("delayed at {} - {}", self.inner.emitted_at, self.note)); + } + } + self.inner } } From 5eafab30ba0721451f5114c5b27b37870bb3955a Mon Sep 17 00:00:00 2001 From: bohan Date: Wed, 7 Jun 2023 00:26:16 +0800 Subject: [PATCH 10/11] feat(expand): emit note for doc comment in macro matcher --- compiler/rustc_expand/src/mbe/macro_rules.rs | 46 +++++++++++++++----- tests/ui/macros/issue-112342-1.rs | 13 ++++++ tests/ui/macros/issue-112342-1.stderr | 37 +++++++++++++++- tests/ui/macros/issue-112342-2.rs | 11 +++++ tests/ui/macros/issue-112342-2.stderr | 24 ++++++++++ 5 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 tests/ui/macros/issue-112342-2.stderr diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 576d636d489..ee9616a0f0a 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -628,6 +628,40 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) // after parsing/expansion. we can report every error in every macro this way. } +fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool { + if seq.separator.is_some() { + false + } else { + let mut is_empty = true; + let mut iter = seq.tts.iter().peekable(); + while let Some(tt) = iter.next() { + match tt { + mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {} + mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => { + let mut now = t; + while let Some(&mbe::TokenTree::Token( + next @ Token { kind: DocComment(..), .. }, + )) = iter.peek() + { + now = next; + iter.next(); + } + let span = t.span.to(now.span); + sess.span_diagnostic.span_note_without_error( + span, + "doc comments are ignored in matcher position", + ); + } + mbe::TokenTree::Sequence(_, sub_seq) + if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore + || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne) => {} + _ => is_empty = false, + } + } + is_empty + } +} + /// Checks that the lhs contains no repetition which could match an empty token /// tree, because then the matcher would hang indefinitely. fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { @@ -644,17 +678,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { } } TokenTree::Sequence(span, seq) => { - if seq.separator.is_none() - && seq.tts.iter().all(|seq_tt| match seq_tt { - TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true, - TokenTree::Token(t) => matches!(t, Token { kind: DocComment(..), .. }), - TokenTree::Sequence(_, sub_seq) => { - sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore - || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne - } - _ => false, - }) - { + if is_empty_token_tree(sess, seq) { let sp = span.entire(); sess.span_diagnostic.span_err(sp, "repetition matches empty token tree"); return false; diff --git a/tests/ui/macros/issue-112342-1.rs b/tests/ui/macros/issue-112342-1.rs index 14fe9bbd97a..bd2abe7f697 100644 --- a/tests/ui/macros/issue-112342-1.rs +++ b/tests/ui/macros/issue-112342-1.rs @@ -33,4 +33,17 @@ macro_rules! m3 { m3! {} + +macro_rules! m4 { + ( + $( + /// + /// + )* + //~^^^^ERROR repetition matches empty token tree + ) => {}; +} + +m4! {} + fn main() {} diff --git a/tests/ui/macros/issue-112342-1.stderr b/tests/ui/macros/issue-112342-1.stderr index 1ba7c0ffd3b..f2d82bf599e 100644 --- a/tests/ui/macros/issue-112342-1.stderr +++ b/tests/ui/macros/issue-112342-1.stderr @@ -1,3 +1,9 @@ +note: doc comments are ignored in matcher position + --> $DIR/issue-112342-1.rs:6:13 + | +LL | /// + | ^^^ + error: repetition matches empty token tree --> $DIR/issue-112342-1.rs:5:10 | @@ -7,6 +13,12 @@ LL | | /// LL | | )* | |_________^ +note: doc comments are ignored in matcher position + --> $DIR/issue-112342-1.rs:17:13 + | +LL | /// + | ^^^ + error: repetition matches empty token tree --> $DIR/issue-112342-1.rs:16:10 | @@ -16,6 +28,12 @@ LL | | /// LL | | )+ | |_________^ +note: doc comments are ignored in matcher position + --> $DIR/issue-112342-1.rs:28:13 + | +LL | /// + | ^^^ + error: repetition matches empty token tree --> $DIR/issue-112342-1.rs:27:10 | @@ -25,5 +43,22 @@ LL | | /// LL | | )? | |_________^ -error: aborting due to 3 previous errors +note: doc comments are ignored in matcher position + --> $DIR/issue-112342-1.rs:40:13 + | +LL | / /// +LL | | /// + | |_______________^ + +error: repetition matches empty token tree + --> $DIR/issue-112342-1.rs:39:10 + | +LL | $( + | __________^ +LL | | /// +LL | | /// +LL | | )* + | |_________^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/macros/issue-112342-2.rs b/tests/ui/macros/issue-112342-2.rs index 1e1d953fa52..e797aff94d2 100644 --- a/tests/ui/macros/issue-112342-2.rs +++ b/tests/ui/macros/issue-112342-2.rs @@ -25,4 +25,15 @@ macro_rules! m2 { m2! {} +macro_rules! m3 { + ( + $( + /// + $tt: tt, + )* + ) => {}; +} + +m3! {} + fn main() {} diff --git a/tests/ui/macros/issue-112342-2.stderr b/tests/ui/macros/issue-112342-2.stderr new file mode 100644 index 00000000000..8c1b6f9471b --- /dev/null +++ b/tests/ui/macros/issue-112342-2.stderr @@ -0,0 +1,24 @@ +note: doc comments are ignored in matcher position + --> $DIR/issue-112342-2.rs:8:13 + | +LL | /// + | ^^^ + +note: doc comments are ignored in matcher position + --> $DIR/issue-112342-2.rs:19:13 + | +LL | /// + | ^^^ + +note: doc comments are ignored in matcher position + --> $DIR/issue-112342-2.rs:21:13 + | +LL | /// + | ^^^ + +note: doc comments are ignored in matcher position + --> $DIR/issue-112342-2.rs:31:13 + | +LL | /// + | ^^^ + From a2ab47f1e57a7192bbdb7f6e90e7776a458b3315 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 7 Jun 2023 05:53:26 -0500 Subject: [PATCH 11/11] download-rustc: Fix `x test core` on MacOS before, this hardcoded `.so` as the extension for dynamically linked objects, which is incorrect everywhere except linux --- src/bootstrap/compile.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 48685f7a9d5..a9e15d89246 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1358,7 +1358,12 @@ impl Step for Sysroot { // newly compiled std, not the downloaded std. add_filtered_files("lib", builder.config.ci_rust_std_contents()); - let filtered_extensions = [OsStr::new("rmeta"), OsStr::new("rlib"), OsStr::new("so")]; + let filtered_extensions = [ + OsStr::new("rmeta"), + OsStr::new("rlib"), + // FIXME: this is wrong when compiler.host != build, but we don't support that today + OsStr::new(std::env::consts::DLL_EXTENSION), + ]; let ci_rustc_dir = builder.ci_rustc_dir(builder.config.build); builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| { if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) {